mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-10-22 06:59:03 +00:00
Merge pull request #115813 from atiratree/controller-aliases
Introduce controller aliases for KCM and CCM
This commit is contained in:
@@ -3,6 +3,7 @@ rules:
|
||||
allowedPrefixes:
|
||||
- k8s.io/kubernetes/cmd/kube-controller-manager/app/options
|
||||
- k8s.io/kubernetes/cmd/kube-controller-manager/app/config
|
||||
- k8s.io/kubernetes/cmd/kube-controller-manager/names
|
||||
- k8s.io/kubernetes/pkg/api/legacyscheme
|
||||
- k8s.io/kubernetes/pkg/api/service
|
||||
- k8s.io/kubernetes/pkg/api/v1/pod
|
||||
|
@@ -31,12 +31,14 @@ import (
|
||||
cloudprovider "k8s.io/cloud-provider"
|
||||
"k8s.io/cloud-provider/app"
|
||||
cloudcontrollerconfig "k8s.io/cloud-provider/app/config"
|
||||
"k8s.io/cloud-provider/names"
|
||||
"k8s.io/cloud-provider/options"
|
||||
"k8s.io/component-base/cli"
|
||||
cliflag "k8s.io/component-base/cli/flag"
|
||||
_ "k8s.io/component-base/metrics/prometheus/clientgo" // load all the prometheus client-go plugins
|
||||
_ "k8s.io/component-base/metrics/prometheus/version" // for version metric registration
|
||||
"k8s.io/klog/v2"
|
||||
kcmnames "k8s.io/kubernetes/cmd/kube-controller-manager/names"
|
||||
// For existing cloud providers, the option to import legacy providers is still available.
|
||||
// e.g. _"k8s.io/legacy-cloud-providers/<provider>"
|
||||
)
|
||||
@@ -48,6 +50,7 @@ func main() {
|
||||
}
|
||||
|
||||
controllerInitializers := app.DefaultInitFuncConstructors
|
||||
controllerAliases := names.CCMControllerAliases()
|
||||
// Here is an example to remove the controller which is not needed.
|
||||
// e.g. remove the cloud-node-lifecycle controller which current cloud provider does not need.
|
||||
//delete(controllerInitializers, "cloud-node-lifecycle")
|
||||
@@ -59,9 +62,9 @@ func main() {
|
||||
nodeIpamController := nodeIPAMController{}
|
||||
nodeIpamController.nodeIPAMControllerOptions.NodeIPAMControllerConfiguration = &nodeIpamController.nodeIPAMControllerConfiguration
|
||||
fss := cliflag.NamedFlagSets{}
|
||||
nodeIpamController.nodeIPAMControllerOptions.AddFlags(fss.FlagSet("nodeipam controller"))
|
||||
nodeIpamController.nodeIPAMControllerOptions.AddFlags(fss.FlagSet(kcmnames.NodeIpamController))
|
||||
|
||||
controllerInitializers["nodeipam"] = app.ControllerInitFuncConstructor{
|
||||
controllerInitializers[kcmnames.NodeIpamController] = app.ControllerInitFuncConstructor{
|
||||
// "node-controller" is the shared identity of all node controllers, including node, node lifecycle, and node ipam.
|
||||
// See https://github.com/kubernetes/kubernetes/pull/72764#issuecomment-453300990 for more context.
|
||||
InitContext: app.ControllerInitContext{
|
||||
@@ -69,8 +72,9 @@ func main() {
|
||||
},
|
||||
Constructor: nodeIpamController.StartNodeIpamControllerWrapper,
|
||||
}
|
||||
controllerAliases["nodeipam"] = kcmnames.NodeIpamController
|
||||
|
||||
command := app.NewCloudControllerManagerCommand(ccmOptions, cloudInitializer, controllerInitializers, fss, wait.NeverStop)
|
||||
command := app.NewCloudControllerManagerCommand(ccmOptions, cloudInitializer, controllerInitializers, controllerAliases, fss, wait.NeverStop)
|
||||
code := cli.Run(command)
|
||||
os.Exit(code)
|
||||
}
|
||||
|
@@ -51,6 +51,7 @@ import (
|
||||
certutil "k8s.io/client-go/util/cert"
|
||||
"k8s.io/client-go/util/keyutil"
|
||||
cloudprovider "k8s.io/cloud-provider"
|
||||
cpnames "k8s.io/cloud-provider/names"
|
||||
cliflag "k8s.io/component-base/cli/flag"
|
||||
"k8s.io/component-base/cli/globalflag"
|
||||
"k8s.io/component-base/configz"
|
||||
@@ -73,6 +74,7 @@ import (
|
||||
|
||||
"k8s.io/kubernetes/cmd/kube-controller-manager/app/config"
|
||||
"k8s.io/kubernetes/cmd/kube-controller-manager/app/options"
|
||||
"k8s.io/kubernetes/cmd/kube-controller-manager/names"
|
||||
kubectrlmgrconfig "k8s.io/kubernetes/pkg/controller/apis/config"
|
||||
serviceaccountcontroller "k8s.io/kubernetes/pkg/controller/serviceaccount"
|
||||
"k8s.io/kubernetes/pkg/serviceaccount"
|
||||
@@ -135,7 +137,7 @@ controller, and serviceaccounts controller.`,
|
||||
}
|
||||
cliflag.PrintFlags(cmd.Flags())
|
||||
|
||||
c, err := s.Config(KnownControllers(), ControllersDisabledByDefault.List())
|
||||
c, err := s.Config(KnownControllers(), ControllersDisabledByDefault.List(), names.KCMControllerAliases())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -154,7 +156,7 @@ controller, and serviceaccounts controller.`,
|
||||
}
|
||||
|
||||
fs := cmd.Flags()
|
||||
namedFlagSets := s.Flags(KnownControllers(), ControllersDisabledByDefault.List())
|
||||
namedFlagSets := s.Flags(KnownControllers(), ControllersDisabledByDefault.List(), names.KCMControllerAliases())
|
||||
verflag.AddFlags(namedFlagSets.FlagSet("global"))
|
||||
globalflag.AddGlobalFlags(namedFlagSets.FlagSet("global"), cmd.Name(), logs.SkipLoggingConfigurationFlags())
|
||||
registerLegacyGlobalFlags(namedFlagSets)
|
||||
@@ -407,7 +409,7 @@ func KnownControllers() []string {
|
||||
// first to ensure that the SA tokens for future controllers will exist. Think very carefully before adding
|
||||
// to this list.
|
||||
ret.Insert(
|
||||
saTokenControllerName,
|
||||
names.ServiceAccountTokenController,
|
||||
)
|
||||
|
||||
return ret.List()
|
||||
@@ -415,12 +417,8 @@ func KnownControllers() []string {
|
||||
|
||||
// ControllersDisabledByDefault is the set of controllers which is disabled by default
|
||||
var ControllersDisabledByDefault = sets.NewString(
|
||||
"bootstrapsigner",
|
||||
"tokencleaner",
|
||||
)
|
||||
|
||||
const (
|
||||
saTokenControllerName = "serviceaccount-token"
|
||||
names.BootstrapSignerController,
|
||||
names.TokenCleanerController,
|
||||
)
|
||||
|
||||
// NewControllerInitializers is a public map of named controller groups (you can start more than one in an init func)
|
||||
@@ -436,55 +434,55 @@ func NewControllerInitializers(loopMode ControllerLoopMode) map[string]InitFunc
|
||||
controllers[name] = fn
|
||||
}
|
||||
|
||||
register("endpoint", startEndpointController)
|
||||
register("endpointslice", startEndpointSliceController)
|
||||
register("endpointslicemirroring", startEndpointSliceMirroringController)
|
||||
register("replicationcontroller", startReplicationController)
|
||||
register("podgc", startPodGCController)
|
||||
register("resourcequota", startResourceQuotaController)
|
||||
register("namespace", startNamespaceController)
|
||||
register("serviceaccount", startServiceAccountController)
|
||||
register("garbagecollector", startGarbageCollectorController)
|
||||
register("daemonset", startDaemonSetController)
|
||||
register("job", startJobController)
|
||||
register("deployment", startDeploymentController)
|
||||
register("replicaset", startReplicaSetController)
|
||||
register("horizontalpodautoscaling", startHPAController)
|
||||
register("disruption", startDisruptionController)
|
||||
register("statefulset", startStatefulSetController)
|
||||
register("cronjob", startCronJobController)
|
||||
register("csrsigning", startCSRSigningController)
|
||||
register("csrapproving", startCSRApprovingController)
|
||||
register("csrcleaner", startCSRCleanerController)
|
||||
register("ttl", startTTLController)
|
||||
register("bootstrapsigner", startBootstrapSignerController)
|
||||
register("tokencleaner", startTokenCleanerController)
|
||||
register("nodeipam", startNodeIpamController)
|
||||
register("nodelifecycle", startNodeLifecycleController)
|
||||
register(names.EndpointsController, startEndpointController)
|
||||
register(names.EndpointSliceController, startEndpointSliceController)
|
||||
register(names.EndpointSliceMirroringController, startEndpointSliceMirroringController)
|
||||
register(names.ReplicationControllerController, startReplicationController)
|
||||
register(names.PodGarbageCollectorController, startPodGCController)
|
||||
register(names.ResourceQuotaController, startResourceQuotaController)
|
||||
register(names.NamespaceController, startNamespaceController)
|
||||
register(names.ServiceAccountController, startServiceAccountController)
|
||||
register(names.GarbageCollectorController, startGarbageCollectorController)
|
||||
register(names.DaemonSetController, startDaemonSetController)
|
||||
register(names.JobController, startJobController)
|
||||
register(names.DeploymentController, startDeploymentController)
|
||||
register(names.ReplicaSetController, startReplicaSetController)
|
||||
register(names.HorizontalPodAutoscalerController, startHPAController)
|
||||
register(names.DisruptionController, startDisruptionController)
|
||||
register(names.StatefulSetController, startStatefulSetController)
|
||||
register(names.CronJobController, startCronJobController)
|
||||
register(names.CertificateSigningRequestSigningController, startCSRSigningController)
|
||||
register(names.CertificateSigningRequestApprovingController, startCSRApprovingController)
|
||||
register(names.CertificateSigningRequestCleanerController, startCSRCleanerController)
|
||||
register(names.TTLController, startTTLController)
|
||||
register(names.BootstrapSignerController, startBootstrapSignerController)
|
||||
register(names.TokenCleanerController, startTokenCleanerController)
|
||||
register(names.NodeIpamController, startNodeIpamController)
|
||||
register(names.NodeLifecycleController, startNodeLifecycleController)
|
||||
if loopMode == IncludeCloudLoops {
|
||||
register("service", startServiceController)
|
||||
register("route", startRouteController)
|
||||
register("cloud-node-lifecycle", startCloudNodeLifecycleController)
|
||||
// TODO: volume controller into the IncludeCloudLoops only set.
|
||||
register(cpnames.ServiceLBController, startServiceController)
|
||||
register(cpnames.NodeRouteController, startRouteController)
|
||||
register(cpnames.CloudNodeLifecycleController, startCloudNodeLifecycleController)
|
||||
// TODO: persistent volume controllers into the IncludeCloudLoops only set.
|
||||
}
|
||||
register("persistentvolume-binder", startPersistentVolumeBinderController)
|
||||
register("attachdetach", startAttachDetachController)
|
||||
register("persistentvolume-expander", startVolumeExpandController)
|
||||
register("clusterrole-aggregation", startClusterRoleAggregrationController)
|
||||
register("pvc-protection", startPVCProtectionController)
|
||||
register("pv-protection", startPVProtectionController)
|
||||
register("ttl-after-finished", startTTLAfterFinishedController)
|
||||
register("root-ca-cert-publisher", startRootCACertPublisher)
|
||||
register("ephemeral-volume", startEphemeralVolumeController)
|
||||
register(names.PersistentVolumeBinderController, startPersistentVolumeBinderController)
|
||||
register(names.PersistentVolumeAttachDetachController, startAttachDetachController)
|
||||
register(names.PersistentVolumeExpanderController, startVolumeExpandController)
|
||||
register(names.ClusterRoleAggregationController, startClusterRoleAggregrationController)
|
||||
register(names.PersistentVolumeClaimProtectionController, startPVCProtectionController)
|
||||
register(names.PersistentVolumeProtectionController, startPVProtectionController)
|
||||
register(names.TTLAfterFinishedController, startTTLAfterFinishedController)
|
||||
register(names.RootCACertificatePublisherController, startRootCACertPublisher)
|
||||
register(names.EphemeralVolumeController, startEphemeralVolumeController)
|
||||
if utilfeature.DefaultFeatureGate.Enabled(genericfeatures.APIServerIdentity) &&
|
||||
utilfeature.DefaultFeatureGate.Enabled(genericfeatures.StorageVersionAPI) {
|
||||
register("storage-version-gc", startStorageVersionGCController)
|
||||
register(names.StorageVersionGarbageCollectorController, startStorageVersionGCController)
|
||||
}
|
||||
if utilfeature.DefaultFeatureGate.Enabled(kubefeatures.DynamicResourceAllocation) {
|
||||
register("resource-claim-controller", startResourceClaimController)
|
||||
register(names.ResourceClaimController, startResourceClaimController)
|
||||
}
|
||||
if utilfeature.DefaultFeatureGate.Enabled(kubefeatures.LegacyServiceAccountTokenCleanUp) {
|
||||
register("legacy-service-account-token-cleaner", startLegacySATokenCleaner)
|
||||
register(names.LegacyServiceAccountTokenCleanerController, startLegacySATokenCleaner)
|
||||
}
|
||||
|
||||
return controllers
|
||||
@@ -655,13 +653,13 @@ type serviceAccountTokenControllerStarter struct {
|
||||
|
||||
func (c serviceAccountTokenControllerStarter) startServiceAccountTokenController(ctx context.Context, controllerContext ControllerContext) (controller.Interface, bool, error) {
|
||||
logger := klog.FromContext(ctx)
|
||||
if !controllerContext.IsControllerEnabled(saTokenControllerName) {
|
||||
logger.Info("Warning: controller is disabled", "controller", saTokenControllerName)
|
||||
if !controllerContext.IsControllerEnabled(names.ServiceAccountTokenController) {
|
||||
logger.Info("Warning: controller is disabled", "controller", names.ServiceAccountTokenController)
|
||||
return nil, false, nil
|
||||
}
|
||||
|
||||
if len(controllerContext.ComponentConfig.SAController.ServiceAccountKeyFile) == 0 {
|
||||
logger.Info("Controller is disabled because there is no private key", "controller", saTokenControllerName)
|
||||
logger.Info("Controller is disabled because there is no private key", "controller", names.ServiceAccountTokenController)
|
||||
return nil, false, nil
|
||||
}
|
||||
privateKey, err := keyutil.PrivateKeyFromFile(controllerContext.ComponentConfig.SAController.ServiceAccountKeyFile)
|
||||
|
93
cmd/kube-controller-manager/app/controllermanager_test.go
Normal file
93
cmd/kube-controller-manager/app/controllermanager_test.go
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
Copyright 2023 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package app
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
cpnames "k8s.io/cloud-provider/names"
|
||||
|
||||
"k8s.io/kubernetes/cmd/kube-controller-manager/names"
|
||||
)
|
||||
|
||||
func TestControllerNamesConsistency(t *testing.T) {
|
||||
controllerNameRegexp := regexp.MustCompile("^[a-z]([-a-z]*[a-z])?$")
|
||||
|
||||
for _, name := range KnownControllers() {
|
||||
if !controllerNameRegexp.MatchString(name) {
|
||||
t.Errorf("name consistency check failed: controller %q must consist of lower case alphabetic characters or '-', and must start and end with an alphabetic character", name)
|
||||
}
|
||||
if !strings.HasSuffix(name, "-controller") {
|
||||
t.Errorf("name consistency check failed: controller %q must have \"-controller\" suffix", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestControllerNamesDeclaration(t *testing.T) {
|
||||
declaredControllers := sets.New(
|
||||
names.ServiceAccountTokenController,
|
||||
names.EndpointsController,
|
||||
names.EndpointSliceController,
|
||||
names.EndpointSliceMirroringController,
|
||||
names.ReplicationControllerController,
|
||||
names.PodGarbageCollectorController,
|
||||
names.ResourceQuotaController,
|
||||
names.NamespaceController,
|
||||
names.ServiceAccountController,
|
||||
names.GarbageCollectorController,
|
||||
names.DaemonSetController,
|
||||
names.JobController,
|
||||
names.DeploymentController,
|
||||
names.ReplicaSetController,
|
||||
names.HorizontalPodAutoscalerController,
|
||||
names.DisruptionController,
|
||||
names.StatefulSetController,
|
||||
names.CronJobController,
|
||||
names.CertificateSigningRequestSigningController,
|
||||
names.CertificateSigningRequestApprovingController,
|
||||
names.CertificateSigningRequestCleanerController,
|
||||
names.TTLController,
|
||||
names.BootstrapSignerController,
|
||||
names.TokenCleanerController,
|
||||
names.NodeIpamController,
|
||||
names.NodeLifecycleController,
|
||||
cpnames.ServiceLBController,
|
||||
cpnames.NodeRouteController,
|
||||
cpnames.CloudNodeLifecycleController,
|
||||
names.PersistentVolumeBinderController,
|
||||
names.PersistentVolumeAttachDetachController,
|
||||
names.PersistentVolumeExpanderController,
|
||||
names.ClusterRoleAggregationController,
|
||||
names.PersistentVolumeClaimProtectionController,
|
||||
names.PersistentVolumeProtectionController,
|
||||
names.TTLAfterFinishedController,
|
||||
names.RootCACertificatePublisherController,
|
||||
names.EphemeralVolumeController,
|
||||
names.StorageVersionGarbageCollectorController,
|
||||
names.ResourceClaimController,
|
||||
names.LegacyServiceAccountTokenCleanerController,
|
||||
)
|
||||
|
||||
for _, name := range KnownControllers() {
|
||||
if !declaredControllers.Has(name) {
|
||||
t.Errorf("name declaration check failed: controller name %q should be declared in \"controller_names.go\" and added to this test", name)
|
||||
}
|
||||
}
|
||||
}
|
@@ -21,6 +21,7 @@ import (
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
|
||||
"k8s.io/kubernetes/cmd/kube-controller-manager/names"
|
||||
endpointslicemirroringconfig "k8s.io/kubernetes/pkg/controller/endpointslicemirroring/config"
|
||||
)
|
||||
|
||||
@@ -44,9 +45,9 @@ func (o *EndpointSliceMirroringControllerOptions) AddFlags(fs *pflag.FlagSet) {
|
||||
return
|
||||
}
|
||||
|
||||
fs.Int32Var(&o.MirroringConcurrentServiceEndpointSyncs, "mirroring-concurrent-service-endpoint-syncs", o.MirroringConcurrentServiceEndpointSyncs, "The number of service endpoint syncing operations that will be done concurrently by the EndpointSliceMirroring controller. Larger number = faster endpoint slice updating, but more CPU (and network) load. Defaults to 5.")
|
||||
fs.Int32Var(&o.MirroringMaxEndpointsPerSubset, "mirroring-max-endpoints-per-subset", o.MirroringMaxEndpointsPerSubset, "The maximum number of endpoints that will be added to an EndpointSlice by the EndpointSliceMirroring controller. More endpoints per slice will result in less endpoint slices, but larger resources. Defaults to 100.")
|
||||
fs.DurationVar(&o.MirroringEndpointUpdatesBatchPeriod.Duration, "mirroring-endpointslice-updates-batch-period", o.MirroringEndpointUpdatesBatchPeriod.Duration, "The length of EndpointSlice updates batching period for EndpointSliceMirroring controller. Processing of EndpointSlice changes will be delayed by this duration to join them with potential upcoming updates and reduce the overall number of EndpointSlice updates. Larger number = higher endpoint programming latency, but lower number of endpoints revision generated")
|
||||
fs.Int32Var(&o.MirroringConcurrentServiceEndpointSyncs, "mirroring-concurrent-service-endpoint-syncs", o.MirroringConcurrentServiceEndpointSyncs, fmt.Sprintf("The number of service endpoint syncing operations that will be done concurrently by the %s. Larger number = faster endpoint slice updating, but more CPU (and network) load. Defaults to 5.", names.EndpointSliceMirroringController))
|
||||
fs.Int32Var(&o.MirroringMaxEndpointsPerSubset, "mirroring-max-endpoints-per-subset", o.MirroringMaxEndpointsPerSubset, fmt.Sprintf("The maximum number of endpoints that will be added to an EndpointSlice by the %s. More endpoints per slice will result in less endpoint slices, but larger resources. Defaults to 100.", names.EndpointSliceMirroringController))
|
||||
fs.DurationVar(&o.MirroringEndpointUpdatesBatchPeriod.Duration, "mirroring-endpointslice-updates-batch-period", o.MirroringEndpointUpdatesBatchPeriod.Duration, fmt.Sprintf("The length of EndpointSlice updates batching period for %s. Processing of EndpointSlice changes will be delayed by this duration to join them with potential upcoming updates and reduce the overall number of EndpointSlice updates. Larger number = higher endpoint programming latency, but lower number of endpoints revision generated", names.EndpointSliceMirroringController))
|
||||
}
|
||||
|
||||
// ApplyTo fills up EndpointSliceMirroringController config with options.
|
||||
|
@@ -17,8 +17,11 @@ limitations under the License.
|
||||
package options
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
|
||||
"k8s.io/kubernetes/cmd/kube-controller-manager/names"
|
||||
nodelifecycleconfig "k8s.io/kubernetes/pkg/controller/nodelifecycle/config"
|
||||
)
|
||||
|
||||
@@ -41,7 +44,7 @@ func (o *NodeLifecycleControllerOptions) AddFlags(fs *pflag.FlagSet) {
|
||||
"where N means number of retries allowed for kubelet to post node status.")
|
||||
fs.Float32Var(&o.NodeEvictionRate, "node-eviction-rate", 0.1, "Number of nodes per second on which pods are deleted in case of node failure when a zone is healthy (see --unhealthy-zone-threshold for definition of healthy/unhealthy). Zone refers to entire cluster in non-multizone clusters.")
|
||||
fs.Float32Var(&o.SecondaryNodeEvictionRate, "secondary-node-eviction-rate", 0.01, "Number of nodes per second on which pods are deleted in case of node failure when a zone is unhealthy (see --unhealthy-zone-threshold for definition of healthy/unhealthy). Zone refers to entire cluster in non-multizone clusters. This value is implicitly overridden to 0 if the cluster size is smaller than --large-cluster-size-threshold.")
|
||||
fs.Int32Var(&o.LargeClusterSizeThreshold, "large-cluster-size-threshold", 50, "Number of nodes from which NodeController treats the cluster as large for the eviction logic purposes. --secondary-node-eviction-rate is implicitly overridden to 0 for clusters this size or smaller.")
|
||||
fs.Int32Var(&o.LargeClusterSizeThreshold, "large-cluster-size-threshold", 50, fmt.Sprintf("Number of nodes from which %s treats the cluster as large for the eviction logic purposes. --secondary-node-eviction-rate is implicitly overridden to 0 for clusters this size or smaller.", names.NodeLifecycleController))
|
||||
fs.Float32Var(&o.UnhealthyZoneThreshold, "unhealthy-zone-threshold", 0.55, "Fraction of Nodes in a zone which needs to be not Ready (minimum 3) for zone to be treated as unhealthy. ")
|
||||
}
|
||||
|
||||
|
@@ -30,6 +30,7 @@ import (
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
"k8s.io/client-go/tools/record"
|
||||
cpnames "k8s.io/cloud-provider/names"
|
||||
cpoptions "k8s.io/cloud-provider/options"
|
||||
cliflag "k8s.io/component-base/cli/flag"
|
||||
"k8s.io/component-base/logs"
|
||||
@@ -38,6 +39,7 @@ import (
|
||||
cmoptions "k8s.io/controller-manager/options"
|
||||
kubectrlmgrconfigv1alpha1 "k8s.io/kube-controller-manager/config/v1alpha1"
|
||||
kubecontrollerconfig "k8s.io/kubernetes/cmd/kube-controller-manager/app/config"
|
||||
"k8s.io/kubernetes/cmd/kube-controller-manager/names"
|
||||
"k8s.io/kubernetes/pkg/cluster/ports"
|
||||
kubectrlmgrconfig "k8s.io/kubernetes/pkg/controller/apis/config"
|
||||
kubectrlmgrconfigscheme "k8s.io/kubernetes/pkg/controller/apis/config/scheme"
|
||||
@@ -224,41 +226,42 @@ func NewDefaultComponentConfig() (kubectrlmgrconfig.KubeControllerManagerConfigu
|
||||
}
|
||||
|
||||
// Flags returns flags for a specific KubeController by section name
|
||||
func (s *KubeControllerManagerOptions) Flags(allControllers []string, disabledByDefaultControllers []string) cliflag.NamedFlagSets {
|
||||
func (s *KubeControllerManagerOptions) Flags(allControllers []string, disabledByDefaultControllers []string, controllerAliases map[string]string) cliflag.NamedFlagSets {
|
||||
fss := cliflag.NamedFlagSets{}
|
||||
s.Generic.AddFlags(&fss, allControllers, disabledByDefaultControllers)
|
||||
s.Generic.AddFlags(&fss, allControllers, disabledByDefaultControllers, controllerAliases)
|
||||
s.KubeCloudShared.AddFlags(fss.FlagSet("generic"))
|
||||
s.ServiceController.AddFlags(fss.FlagSet("service controller"))
|
||||
s.ServiceController.AddFlags(fss.FlagSet(cpnames.ServiceLBController))
|
||||
|
||||
s.SecureServing.AddFlags(fss.FlagSet("secure serving"))
|
||||
s.Authentication.AddFlags(fss.FlagSet("authentication"))
|
||||
s.Authorization.AddFlags(fss.FlagSet("authorization"))
|
||||
|
||||
s.AttachDetachController.AddFlags(fss.FlagSet("attachdetach controller"))
|
||||
s.CSRSigningController.AddFlags(fss.FlagSet("csrsigning controller"))
|
||||
s.DeploymentController.AddFlags(fss.FlagSet("deployment controller"))
|
||||
s.StatefulSetController.AddFlags(fss.FlagSet("statefulset controller"))
|
||||
s.DaemonSetController.AddFlags(fss.FlagSet("daemonset controller"))
|
||||
s.AttachDetachController.AddFlags(fss.FlagSet(names.PersistentVolumeAttachDetachController))
|
||||
s.CSRSigningController.AddFlags(fss.FlagSet(names.CertificateSigningRequestSigningController))
|
||||
s.DeploymentController.AddFlags(fss.FlagSet(names.DeploymentController))
|
||||
s.StatefulSetController.AddFlags(fss.FlagSet(names.StatefulSetController))
|
||||
s.DaemonSetController.AddFlags(fss.FlagSet(names.DaemonSetController))
|
||||
s.DeprecatedFlags.AddFlags(fss.FlagSet("deprecated"))
|
||||
s.EndpointController.AddFlags(fss.FlagSet("endpoint controller"))
|
||||
s.EndpointSliceController.AddFlags(fss.FlagSet("endpointslice controller"))
|
||||
s.EndpointSliceMirroringController.AddFlags(fss.FlagSet("endpointslicemirroring controller"))
|
||||
s.EphemeralVolumeController.AddFlags(fss.FlagSet("ephemeralvolume controller"))
|
||||
s.GarbageCollectorController.AddFlags(fss.FlagSet("garbagecollector controller"))
|
||||
s.HPAController.AddFlags(fss.FlagSet("horizontalpodautoscaling controller"))
|
||||
s.JobController.AddFlags(fss.FlagSet("job controller"))
|
||||
s.CronJobController.AddFlags(fss.FlagSet("cronjob controller"))
|
||||
s.LegacySATokenCleaner.AddFlags(fss.FlagSet("legacy service account token cleaner"))
|
||||
s.NamespaceController.AddFlags(fss.FlagSet("namespace controller"))
|
||||
s.NodeIPAMController.AddFlags(fss.FlagSet("nodeipam controller"))
|
||||
s.NodeLifecycleController.AddFlags(fss.FlagSet("nodelifecycle controller"))
|
||||
s.PersistentVolumeBinderController.AddFlags(fss.FlagSet("persistentvolume-binder controller"))
|
||||
s.PodGCController.AddFlags(fss.FlagSet("podgc controller"))
|
||||
s.ReplicaSetController.AddFlags(fss.FlagSet("replicaset controller"))
|
||||
s.ReplicationController.AddFlags(fss.FlagSet("replicationcontroller"))
|
||||
s.ResourceQuotaController.AddFlags(fss.FlagSet("resourcequota controller"))
|
||||
s.SAController.AddFlags(fss.FlagSet("serviceaccount controller"))
|
||||
s.TTLAfterFinishedController.AddFlags(fss.FlagSet("ttl-after-finished controller"))
|
||||
s.EndpointController.AddFlags(fss.FlagSet(names.EndpointsController))
|
||||
s.EndpointSliceController.AddFlags(fss.FlagSet(names.EndpointSliceController))
|
||||
s.EndpointSliceMirroringController.AddFlags(fss.FlagSet(names.EndpointSliceMirroringController))
|
||||
s.EphemeralVolumeController.AddFlags(fss.FlagSet(names.EphemeralVolumeController))
|
||||
s.GarbageCollectorController.AddFlags(fss.FlagSet(names.GarbageCollectorController))
|
||||
s.HPAController.AddFlags(fss.FlagSet(names.HorizontalPodAutoscalerController))
|
||||
s.JobController.AddFlags(fss.FlagSet(names.JobController))
|
||||
s.CronJobController.AddFlags(fss.FlagSet(names.CronJobController))
|
||||
s.LegacySATokenCleaner.AddFlags(fss.FlagSet(names.LegacyServiceAccountTokenCleanerController))
|
||||
s.NamespaceController.AddFlags(fss.FlagSet(names.NamespaceController))
|
||||
s.NodeIPAMController.AddFlags(fss.FlagSet(names.NodeIpamController))
|
||||
s.NodeLifecycleController.AddFlags(fss.FlagSet(names.NodeLifecycleController))
|
||||
s.PersistentVolumeBinderController.AddFlags(fss.FlagSet(names.PersistentVolumeBinderController))
|
||||
s.PodGCController.AddFlags(fss.FlagSet(names.PodGarbageCollectorController))
|
||||
s.ReplicaSetController.AddFlags(fss.FlagSet(names.ReplicaSetController))
|
||||
s.ReplicationController.AddFlags(fss.FlagSet(names.ReplicationControllerController))
|
||||
s.ResourceQuotaController.AddFlags(fss.FlagSet(names.ResourceQuotaController))
|
||||
s.SAController.AddFlags(fss.FlagSet(names.ServiceAccountController))
|
||||
s.TTLAfterFinishedController.AddFlags(fss.FlagSet(names.TTLAfterFinishedController))
|
||||
|
||||
s.Metrics.AddFlags(fss.FlagSet("metrics"))
|
||||
logsapi.AddFlags(s.Logs, fss.FlagSet("logs"))
|
||||
|
||||
@@ -271,8 +274,8 @@ func (s *KubeControllerManagerOptions) Flags(allControllers []string, disabledBy
|
||||
}
|
||||
|
||||
// ApplyTo fills up controller manager config with options.
|
||||
func (s *KubeControllerManagerOptions) ApplyTo(c *kubecontrollerconfig.Config) error {
|
||||
if err := s.Generic.ApplyTo(&c.ComponentConfig.Generic); err != nil {
|
||||
func (s *KubeControllerManagerOptions) ApplyTo(c *kubecontrollerconfig.Config, allControllers []string, disabledByDefaultControllers []string, controllerAliases map[string]string) error {
|
||||
if err := s.Generic.ApplyTo(&c.ComponentConfig.Generic, allControllers, disabledByDefaultControllers, controllerAliases); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.KubeCloudShared.ApplyTo(&c.ComponentConfig.KubeCloudShared); err != nil {
|
||||
@@ -371,10 +374,10 @@ func (s *KubeControllerManagerOptions) ApplyTo(c *kubecontrollerconfig.Config) e
|
||||
}
|
||||
|
||||
// Validate is used to validate the options and config before launching the controller manager
|
||||
func (s *KubeControllerManagerOptions) Validate(allControllers []string, disabledByDefaultControllers []string) error {
|
||||
func (s *KubeControllerManagerOptions) Validate(allControllers []string, disabledByDefaultControllers []string, controllerAliases map[string]string) error {
|
||||
var errs []error
|
||||
|
||||
errs = append(errs, s.Generic.Validate(allControllers, disabledByDefaultControllers)...)
|
||||
errs = append(errs, s.Generic.Validate(allControllers, disabledByDefaultControllers, controllerAliases)...)
|
||||
errs = append(errs, s.KubeCloudShared.Validate()...)
|
||||
errs = append(errs, s.AttachDetachController.Validate()...)
|
||||
errs = append(errs, s.CSRSigningController.Validate()...)
|
||||
@@ -413,8 +416,8 @@ func (s *KubeControllerManagerOptions) Validate(allControllers []string, disable
|
||||
}
|
||||
|
||||
// Config return a controller manager config objective
|
||||
func (s KubeControllerManagerOptions) Config(allControllers []string, disabledByDefaultControllers []string) (*kubecontrollerconfig.Config, error) {
|
||||
if err := s.Validate(allControllers, disabledByDefaultControllers); err != nil {
|
||||
func (s KubeControllerManagerOptions) Config(allControllers []string, disabledByDefaultControllers []string, controllerAliases map[string]string) (*kubecontrollerconfig.Config, error) {
|
||||
if err := s.Validate(allControllers, disabledByDefaultControllers, controllerAliases); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -446,7 +449,7 @@ func (s KubeControllerManagerOptions) Config(allControllers []string, disabledBy
|
||||
EventBroadcaster: eventBroadcaster,
|
||||
EventRecorder: eventRecorder,
|
||||
}
|
||||
if err := s.ApplyTo(c); err != nil {
|
||||
if err := s.ApplyTo(c, allControllers, disabledByDefaultControllers, controllerAliases); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.Metrics.Apply()
|
||||
|
@@ -166,7 +166,7 @@ var args = []string{
|
||||
func TestAddFlags(t *testing.T) {
|
||||
fs := pflag.NewFlagSet("addflagstest", pflag.ContinueOnError)
|
||||
s, _ := NewKubeControllerManagerOptions()
|
||||
for _, f := range s.Flags([]string{""}, []string{""}).FlagSets {
|
||||
for _, f := range s.Flags([]string{""}, []string{""}, nil).FlagSets {
|
||||
fs.AddFlagSet(f)
|
||||
}
|
||||
|
||||
@@ -457,7 +457,7 @@ func TestApplyTo(t *testing.T) {
|
||||
fs := pflag.NewFlagSet("addflagstest", pflag.ContinueOnError)
|
||||
s, _ := NewKubeControllerManagerOptions()
|
||||
// flag set to parse the args that are required to start the kube controller manager
|
||||
for _, f := range s.Flags([]string{""}, []string{""}).FlagSets {
|
||||
for _, f := range s.Flags([]string{""}, []string{""}, nil).FlagSets {
|
||||
fs.AddFlagSet(f)
|
||||
}
|
||||
|
||||
@@ -648,7 +648,7 @@ func TestApplyTo(t *testing.T) {
|
||||
sort.Sort(sortedGCIgnoredResources(expected.ComponentConfig.GarbageCollectorController.GCIgnoredResources))
|
||||
|
||||
c := &kubecontrollerconfig.Config{}
|
||||
s.ApplyTo(c)
|
||||
s.ApplyTo(c, []string{""}, []string{""}, nil)
|
||||
|
||||
if !reflect.DeepEqual(expected.ComponentConfig, c.ComponentConfig) {
|
||||
t.Errorf("Got different configuration than expected.\nDifference detected on:\n%s", cmp.Diff(expected.ComponentConfig, c.ComponentConfig))
|
||||
@@ -660,24 +660,26 @@ func TestValidateControllersOptions(t *testing.T) {
|
||||
name string
|
||||
expectErrors bool
|
||||
expectedErrorSubString string
|
||||
validate func() []error
|
||||
options interface {
|
||||
Validate() []error
|
||||
}
|
||||
}{
|
||||
{
|
||||
name: "AttachDetachControllerOptions reconciler sync loop period less than one second",
|
||||
expectErrors: true,
|
||||
expectedErrorSubString: "duration time must be greater than one second",
|
||||
validate: (&AttachDetachControllerOptions{
|
||||
options: &AttachDetachControllerOptions{
|
||||
&attachdetachconfig.AttachDetachControllerConfiguration{
|
||||
ReconcilerSyncLoopPeriod: metav1.Duration{Duration: time.Second / 2},
|
||||
DisableAttachDetachReconcilerSync: true,
|
||||
},
|
||||
}).Validate,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "CSRSigningControllerOptions KubeletServingSignerConfiguration no cert file",
|
||||
expectErrors: true,
|
||||
expectedErrorSubString: "cannot specify key without cert",
|
||||
validate: (&CSRSigningControllerOptions{
|
||||
options: &CSRSigningControllerOptions{
|
||||
&csrsigningconfig.CSRSigningControllerConfiguration{
|
||||
ClusterSigningCertFile: "",
|
||||
ClusterSigningKeyFile: "",
|
||||
@@ -699,13 +701,13 @@ func TestValidateControllersOptions(t *testing.T) {
|
||||
KeyFile: "/cluster-signing-legacy-unknown/key-file",
|
||||
},
|
||||
},
|
||||
}).Validate,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "CSRSigningControllerOptions KubeletServingSignerConfiguration no key file",
|
||||
expectErrors: true,
|
||||
expectedErrorSubString: "cannot specify cert without key",
|
||||
validate: (&CSRSigningControllerOptions{
|
||||
options: &CSRSigningControllerOptions{
|
||||
&csrsigningconfig.CSRSigningControllerConfiguration{
|
||||
ClusterSigningCertFile: "",
|
||||
ClusterSigningKeyFile: "",
|
||||
@@ -727,13 +729,13 @@ func TestValidateControllersOptions(t *testing.T) {
|
||||
KeyFile: "/cluster-signing-legacy-unknown/key-file",
|
||||
},
|
||||
},
|
||||
}).Validate,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "CSRSigningControllerOptions KubeletClientSignerConfiguration no cert file",
|
||||
expectErrors: true,
|
||||
expectedErrorSubString: "cannot specify key without cert",
|
||||
validate: (&CSRSigningControllerOptions{
|
||||
options: &CSRSigningControllerOptions{
|
||||
&csrsigningconfig.CSRSigningControllerConfiguration{
|
||||
ClusterSigningCertFile: "",
|
||||
ClusterSigningKeyFile: "",
|
||||
@@ -755,13 +757,13 @@ func TestValidateControllersOptions(t *testing.T) {
|
||||
KeyFile: "/cluster-signing-legacy-unknown/key-file",
|
||||
},
|
||||
},
|
||||
}).Validate,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "CSRSigningControllerOptions KubeletClientSignerConfiguration no key file",
|
||||
expectErrors: true,
|
||||
expectedErrorSubString: "cannot specify cert without key",
|
||||
validate: (&CSRSigningControllerOptions{
|
||||
options: &CSRSigningControllerOptions{
|
||||
&csrsigningconfig.CSRSigningControllerConfiguration{
|
||||
ClusterSigningCertFile: "",
|
||||
ClusterSigningKeyFile: "",
|
||||
@@ -783,13 +785,13 @@ func TestValidateControllersOptions(t *testing.T) {
|
||||
KeyFile: "/cluster-signing-legacy-unknown/key-file",
|
||||
},
|
||||
},
|
||||
}).Validate,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "CSRSigningControllerOptions KubeAPIServerClientSignerConfiguration no cert file",
|
||||
expectErrors: true,
|
||||
expectedErrorSubString: "cannot specify key without cert",
|
||||
validate: (&CSRSigningControllerOptions{
|
||||
options: &CSRSigningControllerOptions{
|
||||
&csrsigningconfig.CSRSigningControllerConfiguration{
|
||||
ClusterSigningCertFile: "",
|
||||
ClusterSigningKeyFile: "",
|
||||
@@ -811,13 +813,13 @@ func TestValidateControllersOptions(t *testing.T) {
|
||||
KeyFile: "/cluster-signing-legacy-unknown/key-file",
|
||||
},
|
||||
},
|
||||
}).Validate,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "CSRSigningControllerOptions KubeAPIServerClientSignerConfiguration no key file",
|
||||
expectErrors: true,
|
||||
expectedErrorSubString: "cannot specify cert without key",
|
||||
validate: (&CSRSigningControllerOptions{
|
||||
options: &CSRSigningControllerOptions{
|
||||
&csrsigningconfig.CSRSigningControllerConfiguration{
|
||||
ClusterSigningCertFile: "",
|
||||
ClusterSigningKeyFile: "",
|
||||
@@ -839,13 +841,13 @@ func TestValidateControllersOptions(t *testing.T) {
|
||||
KeyFile: "/cluster-signing-legacy-unknown/key-file",
|
||||
},
|
||||
},
|
||||
}).Validate,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "CSRSigningControllerOptions LegacyUnknownSignerConfiguration no cert file",
|
||||
expectErrors: true,
|
||||
expectedErrorSubString: "cannot specify key without cert",
|
||||
validate: (&CSRSigningControllerOptions{
|
||||
options: &CSRSigningControllerOptions{
|
||||
&csrsigningconfig.CSRSigningControllerConfiguration{
|
||||
ClusterSigningCertFile: "",
|
||||
ClusterSigningKeyFile: "",
|
||||
@@ -867,13 +869,13 @@ func TestValidateControllersOptions(t *testing.T) {
|
||||
KeyFile: "/cluster-signing-legacy-unknown/key-file",
|
||||
},
|
||||
},
|
||||
}).Validate,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "CSRSigningControllerOptions LegacyUnknownSignerConfiguration no key file",
|
||||
expectErrors: true,
|
||||
expectedErrorSubString: "cannot specify cert without key",
|
||||
validate: (&CSRSigningControllerOptions{
|
||||
options: &CSRSigningControllerOptions{
|
||||
&csrsigningconfig.CSRSigningControllerConfiguration{
|
||||
ClusterSigningCertFile: "",
|
||||
ClusterSigningKeyFile: "",
|
||||
@@ -895,13 +897,13 @@ func TestValidateControllersOptions(t *testing.T) {
|
||||
KeyFile: "",
|
||||
},
|
||||
},
|
||||
}).Validate,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "CSRSigningControllerOptions specific file set along with cluster single signing file",
|
||||
expectErrors: true,
|
||||
expectedErrorSubString: "cannot specify --cluster-signing-{cert,key}-file and other --cluster-signing-*-file flags at the same time",
|
||||
validate: (&CSRSigningControllerOptions{
|
||||
options: &CSRSigningControllerOptions{
|
||||
&csrsigningconfig.CSRSigningControllerConfiguration{
|
||||
ClusterSigningCertFile: "/cluster-signing-cert-file",
|
||||
ClusterSigningKeyFile: "/cluster-signing-key-file",
|
||||
@@ -923,111 +925,111 @@ func TestValidateControllersOptions(t *testing.T) {
|
||||
KeyFile: "",
|
||||
},
|
||||
},
|
||||
}).Validate,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "EndpointSliceControllerOptions ConcurrentServiceEndpointSyncs lower than minConcurrentServiceEndpointSyncs (1)",
|
||||
expectErrors: true,
|
||||
expectedErrorSubString: "concurrent-service-endpoint-syncs must not be less than 1",
|
||||
validate: (&EndpointSliceControllerOptions{
|
||||
options: &EndpointSliceControllerOptions{
|
||||
&endpointsliceconfig.EndpointSliceControllerConfiguration{
|
||||
ConcurrentServiceEndpointSyncs: 0,
|
||||
MaxEndpointsPerSlice: 200,
|
||||
},
|
||||
}).Validate,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "EndpointSliceControllerOptions ConcurrentServiceEndpointSyncs greater than maxConcurrentServiceEndpointSyncs (50)",
|
||||
expectErrors: true,
|
||||
expectedErrorSubString: "concurrent-service-endpoint-syncs must not be more than 50",
|
||||
validate: (&EndpointSliceControllerOptions{
|
||||
options: &EndpointSliceControllerOptions{
|
||||
&endpointsliceconfig.EndpointSliceControllerConfiguration{
|
||||
ConcurrentServiceEndpointSyncs: 51,
|
||||
MaxEndpointsPerSlice: 200,
|
||||
},
|
||||
}).Validate,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "EndpointSliceControllerOptions MaxEndpointsPerSlice lower than minMaxEndpointsPerSlice (1)",
|
||||
expectErrors: true,
|
||||
expectedErrorSubString: "max-endpoints-per-slice must not be less than 1",
|
||||
validate: (&EndpointSliceControllerOptions{
|
||||
options: &EndpointSliceControllerOptions{
|
||||
&endpointsliceconfig.EndpointSliceControllerConfiguration{
|
||||
ConcurrentServiceEndpointSyncs: 10,
|
||||
MaxEndpointsPerSlice: 0,
|
||||
},
|
||||
}).Validate,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "EndpointSliceControllerOptions MaxEndpointsPerSlice greater than maxMaxEndpointsPerSlice (1000)",
|
||||
expectErrors: true,
|
||||
expectedErrorSubString: "max-endpoints-per-slice must not be more than 1000",
|
||||
validate: (&EndpointSliceControllerOptions{
|
||||
options: &EndpointSliceControllerOptions{
|
||||
&endpointsliceconfig.EndpointSliceControllerConfiguration{
|
||||
ConcurrentServiceEndpointSyncs: 10,
|
||||
MaxEndpointsPerSlice: 1001,
|
||||
},
|
||||
}).Validate,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "EndpointSliceMirroringControllerOptions MirroringConcurrentServiceEndpointSyncs lower than mirroringMinConcurrentServiceEndpointSyncs (1)",
|
||||
expectErrors: true,
|
||||
expectedErrorSubString: "mirroring-concurrent-service-endpoint-syncs must not be less than 1",
|
||||
validate: (&EndpointSliceMirroringControllerOptions{
|
||||
options: &EndpointSliceMirroringControllerOptions{
|
||||
&endpointslicemirroringconfig.EndpointSliceMirroringControllerConfiguration{
|
||||
MirroringConcurrentServiceEndpointSyncs: 0,
|
||||
MirroringMaxEndpointsPerSubset: 100,
|
||||
},
|
||||
}).Validate,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "EndpointSliceMirroringControllerOptions MirroringConcurrentServiceEndpointSyncs greater than mirroringMaxConcurrentServiceEndpointSyncs (50)",
|
||||
expectErrors: true,
|
||||
expectedErrorSubString: "mirroring-concurrent-service-endpoint-syncs must not be more than 50",
|
||||
validate: (&EndpointSliceMirroringControllerOptions{
|
||||
options: &EndpointSliceMirroringControllerOptions{
|
||||
&endpointslicemirroringconfig.EndpointSliceMirroringControllerConfiguration{
|
||||
MirroringConcurrentServiceEndpointSyncs: 51,
|
||||
MirroringMaxEndpointsPerSubset: 100,
|
||||
},
|
||||
}).Validate,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "EndpointSliceMirroringControllerOptions MirroringMaxEndpointsPerSubset lower than mirroringMinMaxEndpointsPerSubset (1)",
|
||||
expectErrors: true,
|
||||
expectedErrorSubString: "mirroring-max-endpoints-per-subset must not be less than 1",
|
||||
validate: (&EndpointSliceMirroringControllerOptions{
|
||||
options: &EndpointSliceMirroringControllerOptions{
|
||||
&endpointslicemirroringconfig.EndpointSliceMirroringControllerConfiguration{
|
||||
MirroringConcurrentServiceEndpointSyncs: 10,
|
||||
MirroringMaxEndpointsPerSubset: 0,
|
||||
},
|
||||
}).Validate,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "EndpointSliceMirroringControllerOptions MirroringMaxEndpointsPerSubset greater than mirroringMaxMaxEndpointsPerSubset (1000)",
|
||||
expectErrors: true,
|
||||
expectedErrorSubString: "mirroring-max-endpoints-per-subset must not be more than 1000",
|
||||
validate: (&EndpointSliceMirroringControllerOptions{
|
||||
options: &EndpointSliceMirroringControllerOptions{
|
||||
&endpointslicemirroringconfig.EndpointSliceMirroringControllerConfiguration{
|
||||
MirroringConcurrentServiceEndpointSyncs: 10,
|
||||
MirroringMaxEndpointsPerSubset: 1001,
|
||||
},
|
||||
}).Validate,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "EphemeralVolumeControllerOptions ConcurrentEphemeralVolumeSyncs equal 0",
|
||||
expectErrors: true,
|
||||
expectedErrorSubString: "concurrent-ephemeralvolume-syncs must be greater than 0",
|
||||
validate: (&EphemeralVolumeControllerOptions{
|
||||
options: &EphemeralVolumeControllerOptions{
|
||||
&ephemeralvolumeconfig.EphemeralVolumeControllerConfiguration{
|
||||
ConcurrentEphemeralVolumeSyncs: 0,
|
||||
},
|
||||
}).Validate,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "HPAControllerOptions ConcurrentHorizontalPodAutoscalerSyncs equal 0",
|
||||
expectErrors: true,
|
||||
expectedErrorSubString: "concurrent-horizontal-pod-autoscaler-syncs must be greater than 0",
|
||||
validate: (&HPAControllerOptions{
|
||||
options: &HPAControllerOptions{
|
||||
&poautosclerconfig.HPAControllerConfiguration{
|
||||
ConcurrentHorizontalPodAutoscalerSyncs: 0,
|
||||
HorizontalPodAutoscalerSyncPeriod: metav1.Duration{Duration: 45 * time.Second},
|
||||
@@ -1038,99 +1040,99 @@ func TestValidateControllersOptions(t *testing.T) {
|
||||
HorizontalPodAutoscalerInitialReadinessDelay: metav1.Duration{Duration: 50 * time.Second},
|
||||
HorizontalPodAutoscalerTolerance: 0.1,
|
||||
},
|
||||
}).Validate,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "NodeIPAMControllerOptions service cluster ip range more than two entries",
|
||||
expectErrors: true,
|
||||
expectedErrorSubString: "--service-cluster-ip-range can not contain more than two entries",
|
||||
validate: (&NodeIPAMControllerOptions{
|
||||
options: &NodeIPAMControllerOptions{
|
||||
&nodeipamconfig.NodeIPAMControllerConfiguration{
|
||||
ServiceCIDR: "10.0.0.0/16,244.0.0.0/16,3000::/108",
|
||||
NodeCIDRMaskSize: 48,
|
||||
NodeCIDRMaskSizeIPv4: 48,
|
||||
NodeCIDRMaskSizeIPv6: 108,
|
||||
},
|
||||
}).Validate,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "StatefulSetControllerOptions ConcurrentStatefulSetSyncs equal 0",
|
||||
expectErrors: true,
|
||||
expectedErrorSubString: "concurrent-statefulset-syncs must be greater than 0",
|
||||
validate: (&StatefulSetControllerOptions{
|
||||
options: &StatefulSetControllerOptions{
|
||||
&statefulsetconfig.StatefulSetControllerConfiguration{
|
||||
ConcurrentStatefulSetSyncs: 0,
|
||||
},
|
||||
}).Validate,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "JobControllerOptions ConcurrentJobSyncs equal 0",
|
||||
expectErrors: true,
|
||||
expectedErrorSubString: "concurrent-job-syncs must be greater than 0",
|
||||
validate: (&JobControllerOptions{
|
||||
options: &JobControllerOptions{
|
||||
&jobconfig.JobControllerConfiguration{
|
||||
ConcurrentJobSyncs: 0,
|
||||
},
|
||||
}).Validate,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "CronJobControllerOptions ConcurrentCronJobSyncs equal 0",
|
||||
expectErrors: true,
|
||||
expectedErrorSubString: "concurrent-cron-job-syncs must be greater than 0",
|
||||
validate: (&CronJobControllerOptions{
|
||||
options: &CronJobControllerOptions{
|
||||
&cronjobconfig.CronJobControllerConfiguration{
|
||||
ConcurrentCronJobSyncs: 0,
|
||||
},
|
||||
}).Validate,
|
||||
},
|
||||
},
|
||||
/* empty errs */
|
||||
{
|
||||
name: "CronJobControllerOptions",
|
||||
expectErrors: false,
|
||||
validate: (&CronJobControllerOptions{
|
||||
options: &CronJobControllerOptions{
|
||||
&cronjobconfig.CronJobControllerConfiguration{
|
||||
ConcurrentCronJobSyncs: 10,
|
||||
},
|
||||
}).Validate,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "DaemonSetControllerOptions",
|
||||
expectErrors: false,
|
||||
validate: (&DaemonSetControllerOptions{
|
||||
options: &DaemonSetControllerOptions{
|
||||
&daemonconfig.DaemonSetControllerConfiguration{
|
||||
ConcurrentDaemonSetSyncs: 2,
|
||||
},
|
||||
}).Validate,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "DeploymentControllerOptions",
|
||||
expectErrors: false,
|
||||
validate: (&DeploymentControllerOptions{
|
||||
options: &DeploymentControllerOptions{
|
||||
&deploymentconfig.DeploymentControllerConfiguration{
|
||||
ConcurrentDeploymentSyncs: 10,
|
||||
},
|
||||
}).Validate,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "DeprecatedControllerOptions",
|
||||
expectErrors: false,
|
||||
validate: (&DeprecatedControllerOptions{
|
||||
options: &DeprecatedControllerOptions{
|
||||
&kubectrlmgrconfig.DeprecatedControllerConfiguration{},
|
||||
}).Validate,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "EndpointControllerOptions",
|
||||
expectErrors: false,
|
||||
validate: (&EndpointControllerOptions{
|
||||
options: &EndpointControllerOptions{
|
||||
&endpointconfig.EndpointControllerConfiguration{
|
||||
ConcurrentEndpointSyncs: 10,
|
||||
},
|
||||
}).Validate,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "GarbageCollectorControllerOptions",
|
||||
expectErrors: false,
|
||||
validate: (&GarbageCollectorControllerOptions{
|
||||
options: &GarbageCollectorControllerOptions{
|
||||
&garbagecollectorconfig.GarbageCollectorControllerConfiguration{
|
||||
ConcurrentGCSyncs: 30,
|
||||
GCIgnoredResources: []garbagecollectorconfig.GroupResource{
|
||||
@@ -1139,31 +1141,31 @@ func TestValidateControllersOptions(t *testing.T) {
|
||||
},
|
||||
EnableGarbageCollector: false,
|
||||
},
|
||||
}).Validate,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "JobControllerOptions",
|
||||
expectErrors: false,
|
||||
validate: (&JobControllerOptions{
|
||||
options: &JobControllerOptions{
|
||||
&jobconfig.JobControllerConfiguration{
|
||||
ConcurrentJobSyncs: 10,
|
||||
},
|
||||
}).Validate,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "NamespaceControllerOptions",
|
||||
expectErrors: false,
|
||||
validate: (&NamespaceControllerOptions{
|
||||
options: &NamespaceControllerOptions{
|
||||
&namespaceconfig.NamespaceControllerConfiguration{
|
||||
NamespaceSyncPeriod: metav1.Duration{Duration: 10 * time.Minute},
|
||||
ConcurrentNamespaceSyncs: 20,
|
||||
},
|
||||
}).Validate,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "NodeLifecycleControllerOptions",
|
||||
expectErrors: false,
|
||||
validate: (&NodeLifecycleControllerOptions{
|
||||
options: &NodeLifecycleControllerOptions{
|
||||
&nodelifecycleconfig.NodeLifecycleControllerConfiguration{
|
||||
NodeEvictionRate: 0.2,
|
||||
SecondaryNodeEvictionRate: 0.05,
|
||||
@@ -1172,78 +1174,78 @@ func TestValidateControllersOptions(t *testing.T) {
|
||||
LargeClusterSizeThreshold: 100,
|
||||
UnhealthyZoneThreshold: 0.6,
|
||||
},
|
||||
}).Validate,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "PodGCControllerOptions",
|
||||
expectErrors: false,
|
||||
validate: (&PodGCControllerOptions{
|
||||
options: &PodGCControllerOptions{
|
||||
&podgcconfig.PodGCControllerConfiguration{
|
||||
TerminatedPodGCThreshold: 12000,
|
||||
},
|
||||
}).Validate,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ReplicaSetControllerOptions",
|
||||
expectErrors: false,
|
||||
validate: (&ReplicaSetControllerOptions{
|
||||
options: &ReplicaSetControllerOptions{
|
||||
&replicasetconfig.ReplicaSetControllerConfiguration{
|
||||
ConcurrentRSSyncs: 10,
|
||||
},
|
||||
}).Validate,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ReplicationControllerOptions",
|
||||
expectErrors: false,
|
||||
validate: (&ReplicationControllerOptions{
|
||||
options: &ReplicationControllerOptions{
|
||||
&replicationconfig.ReplicationControllerConfiguration{
|
||||
ConcurrentRCSyncs: 10,
|
||||
},
|
||||
}).Validate,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ResourceQuotaControllerOptions",
|
||||
expectErrors: false,
|
||||
validate: (&ResourceQuotaControllerOptions{
|
||||
options: &ResourceQuotaControllerOptions{
|
||||
&resourcequotaconfig.ResourceQuotaControllerConfiguration{
|
||||
ResourceQuotaSyncPeriod: metav1.Duration{Duration: 10 * time.Minute},
|
||||
ConcurrentResourceQuotaSyncs: 10,
|
||||
},
|
||||
}).Validate,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "SAControllerOptions",
|
||||
expectErrors: false,
|
||||
validate: (&SAControllerOptions{
|
||||
options: &SAControllerOptions{
|
||||
&serviceaccountconfig.SAControllerConfiguration{
|
||||
ServiceAccountKeyFile: "/service-account-private-key",
|
||||
ConcurrentSATokenSyncs: 10,
|
||||
},
|
||||
}).Validate,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "LegacySATokenCleanerOptions",
|
||||
expectErrors: false,
|
||||
validate: (&LegacySATokenCleanerOptions{
|
||||
options: &LegacySATokenCleanerOptions{
|
||||
&serviceaccountconfig.LegacySATokenCleanerConfiguration{
|
||||
CleanUpPeriod: metav1.Duration{Duration: 24 * 365 * time.Hour},
|
||||
},
|
||||
}).Validate,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "TTLAfterFinishedControllerOptions",
|
||||
expectErrors: false,
|
||||
validate: (&TTLAfterFinishedControllerOptions{
|
||||
options: &TTLAfterFinishedControllerOptions{
|
||||
&ttlafterfinishedconfig.TTLAfterFinishedControllerConfiguration{
|
||||
ConcurrentTTLSyncs: 8,
|
||||
},
|
||||
}).Validate,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
errs := tc.validate()
|
||||
errs := tc.options.Validate()
|
||||
if len(errs) > 0 && !tc.expectErrors {
|
||||
t.Errorf("expected no errors, errors found %+v", errs)
|
||||
}
|
||||
@@ -1270,11 +1272,55 @@ func TestValidateControllerManagerOptions(t *testing.T) {
|
||||
|
||||
opts.EndpointSliceController.MaxEndpointsPerSlice = 1001 // max endpoints per slice should be a positive integer <= 1000
|
||||
|
||||
if err := opts.Validate([]string{"*"}, []string{""}); err == nil {
|
||||
if err := opts.Validate([]string{"*"}, []string{""}, nil); err == nil {
|
||||
t.Error("expected error, no error found")
|
||||
}
|
||||
}
|
||||
|
||||
func TestControllerManagerAliases(t *testing.T) {
|
||||
opts, err := NewKubeControllerManagerOptions()
|
||||
if err != nil {
|
||||
t.Errorf("expected no error, error found %+v", err)
|
||||
}
|
||||
opts.Generic.Controllers = []string{"deployment", "-job", "-cronjob-controller", "podgc", "token-cleaner-controller"}
|
||||
expectedControllers := []string{"deployment-controller", "-job-controller", "-cronjob-controller", "pod-garbage-collector-controller", "token-cleaner-controller"}
|
||||
|
||||
allControllers := []string{
|
||||
"bootstrap-signer-controller",
|
||||
"job-controller",
|
||||
"deployment-controller",
|
||||
"cronjob-controller",
|
||||
"namespace-controller",
|
||||
"pod-garbage-collector-controller",
|
||||
"token-cleaner-controller",
|
||||
}
|
||||
disabledByDefaultControllers := []string{
|
||||
"bootstrap-signer-controller",
|
||||
"token-cleaner-controller",
|
||||
}
|
||||
controllerAliases := map[string]string{
|
||||
"bootstrapsigner": "bootstrap-signer-controller",
|
||||
"job": "job-controller",
|
||||
"deployment": "deployment-controller",
|
||||
"cronjob": "cronjob-controller",
|
||||
"namespace": "namespace-controller",
|
||||
"podgc": "pod-garbage-collector-controller",
|
||||
"tokencleaner": "token-cleaner-controller",
|
||||
}
|
||||
|
||||
if err := opts.Validate(allControllers, disabledByDefaultControllers, controllerAliases); err != nil {
|
||||
t.Errorf("expected no error, error found %v", err)
|
||||
}
|
||||
|
||||
cfg := &kubecontrollerconfig.Config{}
|
||||
if err := opts.ApplyTo(cfg, allControllers, disabledByDefaultControllers, controllerAliases); err != nil {
|
||||
t.Errorf("expected no error, error found %v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(cfg.ComponentConfig.Generic.Controllers, expectedControllers) {
|
||||
t.Errorf("controller aliases not resolved correctly, expected %+v, got %+v", expectedControllers, cfg.ComponentConfig.Generic.Controllers)
|
||||
}
|
||||
}
|
||||
|
||||
type sortedGCIgnoredResources []garbagecollectorconfig.GroupResource
|
||||
|
||||
func (r sortedGCIgnoredResources) Len() int {
|
||||
|
@@ -17,8 +17,11 @@ limitations under the License.
|
||||
package options
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
|
||||
"k8s.io/kubernetes/cmd/kube-controller-manager/names"
|
||||
ttlafterfinishedconfig "k8s.io/kubernetes/pkg/controller/ttlafterfinished/config"
|
||||
)
|
||||
|
||||
@@ -33,7 +36,7 @@ func (o *TTLAfterFinishedControllerOptions) AddFlags(fs *pflag.FlagSet) {
|
||||
return
|
||||
}
|
||||
|
||||
fs.Int32Var(&o.ConcurrentTTLSyncs, "concurrent-ttl-after-finished-syncs", o.ConcurrentTTLSyncs, "The number of TTL-after-finished controller workers that are allowed to sync concurrently.")
|
||||
fs.Int32Var(&o.ConcurrentTTLSyncs, "concurrent-ttl-after-finished-syncs", o.ConcurrentTTLSyncs, fmt.Sprintf("The number of %s workers that are allowed to sync concurrently.", names.TTLAfterFinishedController))
|
||||
}
|
||||
|
||||
// ApplyTo fills up TTLAfterFinishedController config with options.
|
||||
|
@@ -28,11 +28,12 @@ import (
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
"k8s.io/kubernetes/cmd/kube-controller-manager/app"
|
||||
kubecontrollerconfig "k8s.io/kubernetes/cmd/kube-controller-manager/app/config"
|
||||
"k8s.io/kubernetes/cmd/kube-controller-manager/app/options"
|
||||
|
||||
"k8s.io/klog/v2"
|
||||
"k8s.io/kubernetes/cmd/kube-controller-manager/names"
|
||||
)
|
||||
|
||||
// TearDownFunc is to be called to tear down a test server.
|
||||
@@ -89,8 +90,8 @@ func StartTestServer(ctx context.Context, customFlags []string) (result TestServ
|
||||
if err != nil {
|
||||
return TestServer{}, err
|
||||
}
|
||||
all, disabled := app.KnownControllers(), app.ControllersDisabledByDefault.List()
|
||||
namedFlagSets := s.Flags(all, disabled)
|
||||
all, disabled, aliases := app.KnownControllers(), app.ControllersDisabledByDefault.List(), names.KCMControllerAliases()
|
||||
namedFlagSets := s.Flags(all, disabled, aliases)
|
||||
for _, f := range namedFlagSets.FlagSets {
|
||||
fs.AddFlagSet(f)
|
||||
}
|
||||
@@ -106,7 +107,7 @@ func StartTestServer(ctx context.Context, customFlags []string) (result TestServ
|
||||
logger.Info("kube-controller-manager will listen securely", "port", s.SecureServing.BindPort)
|
||||
}
|
||||
|
||||
config, err := s.Config(all, disabled)
|
||||
config, err := s.Config(all, disabled, aliases)
|
||||
if err != nil {
|
||||
return result, fmt.Errorf("failed to create config from options: %v", err)
|
||||
}
|
||||
|
140
cmd/kube-controller-manager/names/controller_names.go
Normal file
140
cmd/kube-controller-manager/names/controller_names.go
Normal file
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
Copyright 2023 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package names
|
||||
|
||||
import cpnames "k8s.io/cloud-provider/names"
|
||||
|
||||
// Canonical controller names
|
||||
//
|
||||
// NAMING CONVENTIONS
|
||||
// 1. naming should be consistent across the controllers
|
||||
// 2. use of shortcuts should be avoided, unless they are well-known non-Kubernetes shortcuts
|
||||
// 3. Kubernetes' resources should be written together without a hyphen ("-")
|
||||
//
|
||||
// CHANGE POLICY
|
||||
// The controller names should be treated as IDs.
|
||||
// They can only be changed if absolutely necessary. For example if an inappropriate name was chosen in the past, or if the scope of the controller changes.
|
||||
// When a name is changed, the old name should be aliased in KCMControllerAliases, while preserving all old aliases.
|
||||
// This is done to achieve backwards compatibility
|
||||
//
|
||||
// USE CASES
|
||||
// The following places should use the controller name constants, when:
|
||||
// 1. registering a controller in app.NewControllerInitializers or app.KnownControllers:
|
||||
// 1.1. disabling a controller by default in app.ControllersDisabledByDefault
|
||||
// 1.2. checking if IsControllerEnabled
|
||||
// 1.3. defining an alias in KCMControllerAliases (for backwards compatibility only)
|
||||
// 2. used anywhere inside the controller itself:
|
||||
// 2.1. [TODO] logger component should be configured with the controller name by calling LoggerWithName
|
||||
// 2.2. [TODO] logging should use a canonical controller name when referencing a controller (Eg. Starting X, Shutting down X)
|
||||
// 2.3. [TODO] emitted events should have an EventSource.Component set to the controller name (usually when initializing an EventRecorder)
|
||||
// 2.4. [TODO] registering ControllerManagerMetrics with ControllerStarted and ControllerStopped
|
||||
// 2.5. [TODO] calling WaitForNamedCacheSync
|
||||
// 3. defining controller options for "--help" command or generated documentation
|
||||
// 3.1. controller name should be used to create a pflag.FlagSet when registering controller options (the name is rendered in a controller flag group header)
|
||||
// 3.2. when defined flag's help mentions a controller name
|
||||
// 4. defining a new service account for a new controller (old controllers may have inconsistent service accounts to stay backwards compatible)
|
||||
const (
|
||||
ServiceAccountTokenController = "serviceaccount-token-controller"
|
||||
EndpointsController = "endpoints-controller"
|
||||
EndpointSliceController = "endpointslice-controller"
|
||||
EndpointSliceMirroringController = "endpointslice-mirroring-controller"
|
||||
ReplicationControllerController = "replicationcontroller-controller"
|
||||
PodGarbageCollectorController = "pod-garbage-collector-controller"
|
||||
ResourceQuotaController = "resourcequota-controller"
|
||||
NamespaceController = "namespace-controller"
|
||||
ServiceAccountController = "serviceaccount-controller"
|
||||
GarbageCollectorController = "garbage-collector-controller"
|
||||
DaemonSetController = "daemonset-controller"
|
||||
JobController = "job-controller"
|
||||
DeploymentController = "deployment-controller"
|
||||
ReplicaSetController = "replicaset-controller"
|
||||
HorizontalPodAutoscalerController = "horizontal-pod-autoscaler-controller"
|
||||
DisruptionController = "disruption-controller"
|
||||
StatefulSetController = "statefulset-controller"
|
||||
CronJobController = "cronjob-controller"
|
||||
CertificateSigningRequestSigningController = "certificatesigningrequest-signing-controller"
|
||||
CertificateSigningRequestApprovingController = "certificatesigningrequest-approving-controller"
|
||||
CertificateSigningRequestCleanerController = "certificatesigningrequest-cleaner-controller"
|
||||
TTLController = "ttl-controller"
|
||||
BootstrapSignerController = "bootstrap-signer-controller"
|
||||
TokenCleanerController = "token-cleaner-controller"
|
||||
NodeIpamController = "node-ipam-controller"
|
||||
NodeLifecycleController = "node-lifecycle-controller"
|
||||
PersistentVolumeBinderController = "persistentvolume-binder-controller"
|
||||
PersistentVolumeAttachDetachController = "persistentvolume-attach-detach-controller"
|
||||
PersistentVolumeExpanderController = "persistentvolume-expander-controller"
|
||||
ClusterRoleAggregationController = "clusterrole-aggregation-controller"
|
||||
PersistentVolumeClaimProtectionController = "persistentvolumeclaim-protection-controller"
|
||||
PersistentVolumeProtectionController = "persistentvolume-protection-controller"
|
||||
TTLAfterFinishedController = "ttl-after-finished-controller"
|
||||
RootCACertificatePublisherController = "root-ca-certificate-publisher-controller"
|
||||
EphemeralVolumeController = "ephemeral-volume-controller"
|
||||
StorageVersionGarbageCollectorController = "storageversion-garbage-collector-controller"
|
||||
ResourceClaimController = "resourceclaim-controller"
|
||||
LegacyServiceAccountTokenCleanerController = "legacy-serviceaccount-token-cleaner-controller"
|
||||
)
|
||||
|
||||
// KCMControllerAliases returns a mapping of aliases to canonical controller names
|
||||
//
|
||||
// These aliases ensure backwards compatibility and should never be removed!
|
||||
// Only addition of new aliases is allowed, and only when a canonical name is changed (please see CHANGE POLICY of controller names)
|
||||
func KCMControllerAliases() map[string]string {
|
||||
// return a new reference to achieve immutability of the mapping
|
||||
return map[string]string{
|
||||
"serviceaccount-token": ServiceAccountTokenController,
|
||||
"endpoint": EndpointsController,
|
||||
"endpointslice": EndpointSliceController,
|
||||
"endpointslicemirroring": EndpointSliceMirroringController,
|
||||
"replicationcontroller": ReplicationControllerController,
|
||||
"podgc": PodGarbageCollectorController,
|
||||
"resourcequota": ResourceQuotaController,
|
||||
"namespace": NamespaceController,
|
||||
"serviceaccount": ServiceAccountController,
|
||||
"garbagecollector": GarbageCollectorController,
|
||||
"daemonset": DaemonSetController,
|
||||
"job": JobController,
|
||||
"deployment": DeploymentController,
|
||||
"replicaset": ReplicaSetController,
|
||||
"horizontalpodautoscaling": HorizontalPodAutoscalerController,
|
||||
"disruption": DisruptionController,
|
||||
"statefulset": StatefulSetController,
|
||||
"cronjob": CronJobController,
|
||||
"csrsigning": CertificateSigningRequestSigningController,
|
||||
"csrapproving": CertificateSigningRequestApprovingController,
|
||||
"csrcleaner": CertificateSigningRequestCleanerController,
|
||||
"ttl": TTLController,
|
||||
"bootstrapsigner": BootstrapSignerController,
|
||||
"tokencleaner": TokenCleanerController,
|
||||
"nodeipam": NodeIpamController,
|
||||
"nodelifecycle": NodeLifecycleController,
|
||||
"service": cpnames.ServiceLBController,
|
||||
"route": cpnames.NodeRouteController,
|
||||
"cloud-node-lifecycle": cpnames.CloudNodeLifecycleController,
|
||||
"persistentvolume-binder": PersistentVolumeBinderController,
|
||||
"attachdetach": PersistentVolumeAttachDetachController,
|
||||
"persistentvolume-expander": PersistentVolumeExpanderController,
|
||||
"clusterrole-aggregation": ClusterRoleAggregationController,
|
||||
"pvc-protection": PersistentVolumeClaimProtectionController,
|
||||
"pv-protection": PersistentVolumeProtectionController,
|
||||
"ttl-after-finished": TTLAfterFinishedController,
|
||||
"root-ca-cert-publisher": RootCACertificatePublisherController,
|
||||
"ephemeral-volume": EphemeralVolumeController,
|
||||
"storage-version-gc": StorageVersionGarbageCollectorController,
|
||||
"resource-claim-controller": ResourceClaimController,
|
||||
"legacy-service-account-token-cleaner": LegacyServiceAccountTokenCleanerController,
|
||||
}
|
||||
}
|
@@ -22,6 +22,7 @@ import (
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/cloud-provider/names"
|
||||
"k8s.io/cloud-provider/options"
|
||||
cliflag "k8s.io/component-base/cli/flag"
|
||||
"k8s.io/component-base/cli/globalflag"
|
||||
@@ -32,6 +33,7 @@ import (
|
||||
type CommandBuilder struct {
|
||||
webhookConfigs map[string]WebhookConfig
|
||||
controllerInitFuncConstructors map[string]ControllerInitFuncConstructor
|
||||
controllerAliases map[string]string
|
||||
additionalFlags cliflag.NamedFlagSets
|
||||
options *options.CloudControllerManagerOptions
|
||||
cloudInitializer InitCloudFunc
|
||||
@@ -45,6 +47,7 @@ func NewBuilder() *CommandBuilder {
|
||||
cb := CommandBuilder{}
|
||||
cb.webhookConfigs = make(map[string]WebhookConfig)
|
||||
cb.controllerInitFuncConstructors = make(map[string]ControllerInitFuncConstructor)
|
||||
cb.controllerAliases = make(map[string]string)
|
||||
return &cb
|
||||
}
|
||||
|
||||
@@ -56,14 +59,22 @@ func (cb *CommandBuilder) AddFlags(additionalFlags cliflag.NamedFlagSets) {
|
||||
cb.additionalFlags = additionalFlags
|
||||
}
|
||||
|
||||
func (cb *CommandBuilder) RegisterController(name string, constructor ControllerInitFuncConstructor) {
|
||||
func (cb *CommandBuilder) RegisterController(name string, constructor ControllerInitFuncConstructor, aliases map[string]string) {
|
||||
cb.controllerInitFuncConstructors[name] = constructor
|
||||
for key, val := range aliases {
|
||||
if name == val {
|
||||
cb.controllerAliases[key] = val
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (cb *CommandBuilder) RegisterDefaultControllers() {
|
||||
for key, val := range DefaultInitFuncConstructors {
|
||||
cb.controllerInitFuncConstructors[key] = val
|
||||
}
|
||||
for key, val := range names.CCMControllerAliases() {
|
||||
cb.controllerAliases[key] = val
|
||||
}
|
||||
}
|
||||
|
||||
func (cb *CommandBuilder) RegisterWebhook(name string, config WebhookConfig) {
|
||||
@@ -129,7 +140,7 @@ func (cb *CommandBuilder) BuildCommand() *cobra.Command {
|
||||
cliflag.PrintFlags(cmd.Flags())
|
||||
|
||||
config, err := cb.options.Config(ControllerNames(cb.controllerInitFuncConstructors), ControllersDisabledByDefault.List(),
|
||||
WebhookNames(cb.webhookConfigs), WebhooksDisabledByDefault.List())
|
||||
cb.controllerAliases, WebhookNames(cb.webhookConfigs), WebhooksDisabledByDefault.List())
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%v\n", err)
|
||||
return err
|
||||
@@ -156,7 +167,8 @@ func (cb *CommandBuilder) BuildCommand() *cobra.Command {
|
||||
}
|
||||
|
||||
fs := cmd.Flags()
|
||||
namedFlagSets := cb.options.Flags(ControllerNames(cb.controllerInitFuncConstructors), ControllersDisabledByDefault.List(), WebhookNames(cb.webhookConfigs), WebhooksDisabledByDefault.List())
|
||||
namedFlagSets := cb.options.Flags(ControllerNames(cb.controllerInitFuncConstructors), ControllersDisabledByDefault.List(), cb.controllerAliases,
|
||||
WebhookNames(cb.webhookConfigs), WebhooksDisabledByDefault.List())
|
||||
verflag.AddFlags(namedFlagSets.FlagSet("global"))
|
||||
globalflag.AddGlobalFlags(namedFlagSets.FlagSet("global"), cmd.Name())
|
||||
|
||||
|
@@ -43,6 +43,7 @@ import (
|
||||
"k8s.io/client-go/tools/leaderelection/resourcelock"
|
||||
cloudprovider "k8s.io/cloud-provider"
|
||||
cloudcontrollerconfig "k8s.io/cloud-provider/app/config"
|
||||
"k8s.io/cloud-provider/names"
|
||||
"k8s.io/cloud-provider/options"
|
||||
cliflag "k8s.io/component-base/cli/flag"
|
||||
"k8s.io/component-base/cli/globalflag"
|
||||
@@ -80,7 +81,7 @@ const (
|
||||
// NewCloudControllerManagerCommand creates a *cobra.Command object with default parameters
|
||||
// controllerInitFuncConstructors is a map of controller name(as defined by controllers flag in https://kubernetes.io/docs/reference/command-line-tools-reference/kube-controller-manager/#options) to their InitFuncConstructor.
|
||||
// additionalFlags provides controller specific flags to be included in the complete set of controller manager flags
|
||||
func NewCloudControllerManagerCommand(s *options.CloudControllerManagerOptions, cloudInitializer InitCloudFunc, controllerInitFuncConstructors map[string]ControllerInitFuncConstructor, additionalFlags cliflag.NamedFlagSets, stopCh <-chan struct{}) *cobra.Command {
|
||||
func NewCloudControllerManagerCommand(s *options.CloudControllerManagerOptions, cloudInitializer InitCloudFunc, controllerInitFuncConstructors map[string]ControllerInitFuncConstructor, controllerAliases map[string]string, additionalFlags cliflag.NamedFlagSets, stopCh <-chan struct{}) *cobra.Command {
|
||||
logOptions := logs.NewOptions()
|
||||
|
||||
cmd := &cobra.Command{
|
||||
@@ -96,7 +97,7 @@ the cloud specific control loops shipped with Kubernetes.`,
|
||||
return err
|
||||
}
|
||||
|
||||
c, err := s.Config(ControllerNames(controllerInitFuncConstructors), ControllersDisabledByDefault.List(), AllWebhooks, DisabledByDefaultWebhooks)
|
||||
c, err := s.Config(ControllerNames(controllerInitFuncConstructors), ControllersDisabledByDefault.List(), controllerAliases, AllWebhooks, DisabledByDefaultWebhooks)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%v\n", err)
|
||||
return err
|
||||
@@ -123,7 +124,7 @@ the cloud specific control loops shipped with Kubernetes.`,
|
||||
}
|
||||
|
||||
fs := cmd.Flags()
|
||||
namedFlagSets := s.Flags(ControllerNames(controllerInitFuncConstructors), ControllersDisabledByDefault.List(), AllWebhooks, DisabledByDefaultWebhooks)
|
||||
namedFlagSets := s.Flags(ControllerNames(controllerInitFuncConstructors), ControllersDisabledByDefault.List(), controllerAliases, AllWebhooks, DisabledByDefaultWebhooks)
|
||||
|
||||
globalFlagSet := namedFlagSets.FlagSet("global")
|
||||
verflag.AddFlags(globalFlagSet)
|
||||
@@ -441,25 +442,25 @@ var DefaultInitFuncConstructors = map[string]ControllerInitFuncConstructor{
|
||||
// The cloud-node controller shares the "node-controller" identity with the cloud-node-lifecycle
|
||||
// controller for historical reasons. See
|
||||
// https://github.com/kubernetes/kubernetes/pull/72764#issuecomment-453300990 for more context.
|
||||
"cloud-node": {
|
||||
names.CloudNodeController: {
|
||||
InitContext: ControllerInitContext{
|
||||
ClientName: "node-controller",
|
||||
},
|
||||
Constructor: StartCloudNodeControllerWrapper,
|
||||
},
|
||||
"cloud-node-lifecycle": {
|
||||
names.CloudNodeLifecycleController: {
|
||||
InitContext: ControllerInitContext{
|
||||
ClientName: "node-controller",
|
||||
},
|
||||
Constructor: StartCloudNodeLifecycleControllerWrapper,
|
||||
},
|
||||
"service": {
|
||||
names.ServiceLBController: {
|
||||
InitContext: ControllerInitContext{
|
||||
ClientName: "service-controller",
|
||||
},
|
||||
Constructor: StartServiceControllerWrapper,
|
||||
},
|
||||
"route": {
|
||||
names.NodeRouteController: {
|
||||
InitContext: ControllerInitContext{
|
||||
ClientName: "route-controller",
|
||||
},
|
||||
|
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
Copyright 2023 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package app
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/cloud-provider/names"
|
||||
)
|
||||
|
||||
func TestCloudControllerNamesConsistency(t *testing.T) {
|
||||
controllerNameRegexp := regexp.MustCompile("^[a-z]([-a-z]*[a-z])?$")
|
||||
|
||||
for name := range DefaultInitFuncConstructors {
|
||||
if !controllerNameRegexp.MatchString(name) {
|
||||
t.Errorf("name consistency check failed: controller %q must consist of lower case alphabetic characters or '-', and must start and end with an alphabetic character", name)
|
||||
}
|
||||
if !strings.HasSuffix(name, "-controller") {
|
||||
t.Errorf("name consistency check failed: controller %q must have \"-controller\" suffix", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCloudControllerNamesDeclaration(t *testing.T) {
|
||||
declaredControllers := sets.New(
|
||||
names.CloudNodeController,
|
||||
names.ServiceLBController,
|
||||
names.NodeRouteController,
|
||||
names.CloudNodeLifecycleController,
|
||||
)
|
||||
|
||||
for name := range DefaultInitFuncConstructors {
|
||||
if !declaredControllers.Has(name) {
|
||||
t.Errorf("name declaration check failed: controller name %q should be declared in \"controller_names.go\" and added to this test", name)
|
||||
}
|
||||
}
|
||||
}
|
@@ -31,6 +31,7 @@ import (
|
||||
cloudprovider "k8s.io/cloud-provider"
|
||||
"k8s.io/cloud-provider/app"
|
||||
"k8s.io/cloud-provider/app/config"
|
||||
"k8s.io/cloud-provider/names"
|
||||
"k8s.io/cloud-provider/options"
|
||||
cliflag "k8s.io/component-base/cli/flag"
|
||||
"k8s.io/klog/v2"
|
||||
@@ -107,7 +108,7 @@ func StartTestServer(ctx context.Context, customFlags []string) (result TestServ
|
||||
return cloud
|
||||
}
|
||||
fss := cliflag.NamedFlagSets{}
|
||||
command := app.NewCloudControllerManagerCommand(s, cloudInitializer, app.DefaultInitFuncConstructors, fss, stopCh)
|
||||
command := app.NewCloudControllerManagerCommand(s, cloudInitializer, app.DefaultInitFuncConstructors, names.CCMControllerAliases(), fss, stopCh)
|
||||
|
||||
commandArgs := []string{}
|
||||
listeners := []net.Listener{}
|
||||
|
@@ -65,7 +65,7 @@ type KubeCloudSharedConfiguration struct {
|
||||
AllowUntaggedCloud bool
|
||||
// routeReconciliationPeriod is the period for reconciling routes created for Nodes by cloud provider..
|
||||
RouteReconciliationPeriod metav1.Duration
|
||||
// nodeMonitorPeriod is the period for syncing NodeStatus in NodeController.
|
||||
// nodeMonitorPeriod is the period for syncing NodeStatus in CloudNodeLifecycleController.
|
||||
NodeMonitorPeriod metav1.Duration
|
||||
// clusterName is the instance prefix for the cluster.
|
||||
ClusterName string
|
||||
|
69
staging/src/k8s.io/cloud-provider/names/controller_names.go
Normal file
69
staging/src/k8s.io/cloud-provider/names/controller_names.go
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
Copyright 2023 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package names
|
||||
|
||||
// Canonical controller names
|
||||
//
|
||||
// NAMING CONVENTIONS
|
||||
// 1. naming should be consistent across the controllers
|
||||
// 2. use of shortcuts should be avoided, unless they are well-known non-Kubernetes shortcuts
|
||||
// 3. Kubernetes' resources should be written together without a hyphen ("-")
|
||||
//
|
||||
// CHANGE POLICY
|
||||
// The controller names should be treated as IDs.
|
||||
// They can only be changed if absolutely necessary. For example if an inappropriate name was chosen in the past, or if the scope of the controller changes.
|
||||
// When a name is changed, the old name should be aliased in CCMControllerAliases, while preserving all old aliases.
|
||||
// This is done to achieve backwards compatibility
|
||||
//
|
||||
// USE CASES
|
||||
// The following places should use the controller name constants, when:
|
||||
// 1. registering a controller in app.DefaultInitFuncConstructors or sample main.controllerInitializers:
|
||||
// 1.1. disabling a controller by default in app.ControllersDisabledByDefault
|
||||
// 1.2. checking if IsControllerEnabled
|
||||
// 1.3. defining an alias in CCMControllerAliases (for backwards compatibility only)
|
||||
// 2. used anywhere inside the controller itself:
|
||||
// 2.1. [TODO] logger component should be configured with the controller name by calling LoggerWithName
|
||||
// 2.2. [TODO] logging should use a canonical controller name when referencing a controller (Eg. Starting X, Shutting down X)
|
||||
// 2.3. [TODO] emitted events should have an EventSource.Component set to the controller name (usually when initializing an EventRecorder)
|
||||
// 2.4. [TODO] registering ControllerManagerMetrics with ControllerStarted and ControllerStopped
|
||||
// 2.5. [TODO] calling WaitForNamedCacheSync
|
||||
// 3. defining controller options for "--help" command or generated documentation
|
||||
// 3.1. controller name should be used to create a pflag.FlagSet when registering controller options (the name is rendered in a controller flag group header)
|
||||
// 3.2. when defined flag's help mentions a controller name
|
||||
// 4. defining a new service account for a new controller (old controllers may have inconsistent service accounts to stay backwards compatible)
|
||||
// 5. anywhere these controllers are used outside of this module (kube-controller-manager, cloud-provider sample)
|
||||
const (
|
||||
CloudNodeController = "cloud-node-controller"
|
||||
ServiceLBController = "service-lb-controller"
|
||||
NodeRouteController = "node-route-controller"
|
||||
CloudNodeLifecycleController = "cloud-node-lifecycle-controller"
|
||||
)
|
||||
|
||||
// CCMControllerAliases returns a mapping of aliases to canonical controller names
|
||||
//
|
||||
// These aliases ensure backwards compatibility and should never be removed!
|
||||
// Only addition of new aliases is allowed, and only when a canonical name is changed (please see CHANGE POLICY of controller names)
|
||||
func CCMControllerAliases() map[string]string {
|
||||
// return a new reference to achieve immutability of the mapping
|
||||
return map[string]string{
|
||||
"cloud-node": CloudNodeController,
|
||||
"service": ServiceLBController,
|
||||
"route": NodeRouteController,
|
||||
"cloud-node-lifecycle": CloudNodeLifecycleController,
|
||||
}
|
||||
|
||||
}
|
@@ -17,8 +17,12 @@ limitations under the License.
|
||||
package options
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
|
||||
cpconfig "k8s.io/cloud-provider/config"
|
||||
"k8s.io/cloud-provider/names"
|
||||
)
|
||||
|
||||
// KubeCloudSharedOptions holds the options shared between kube-controller-manager
|
||||
@@ -49,13 +53,13 @@ func (o *KubeCloudSharedOptions) AddFlags(fs *pflag.FlagSet) {
|
||||
}
|
||||
|
||||
o.CloudProvider.AddFlags(fs)
|
||||
fs.StringVar(&o.ExternalCloudVolumePlugin, "external-cloud-volume-plugin", o.ExternalCloudVolumePlugin, "The plugin to use when cloud provider is set to external. Can be empty, should only be set when cloud-provider is external. Currently used to allow node and volume controllers to work for in tree cloud providers.")
|
||||
fs.StringVar(&o.ExternalCloudVolumePlugin, "external-cloud-volume-plugin", o.ExternalCloudVolumePlugin, "The plugin to use when cloud provider is set to external. Can be empty, should only be set when cloud-provider is external. Currently used to allow node-ipam-controller, persistentvolume-binder-controller, persistentvolume-expander-controller and attach-detach-controller to work for in tree cloud providers.")
|
||||
fs.BoolVar(&o.UseServiceAccountCredentials, "use-service-account-credentials", o.UseServiceAccountCredentials, "If true, use individual service account credentials for each controller.")
|
||||
fs.BoolVar(&o.AllowUntaggedCloud, "allow-untagged-cloud", false, "Allow the cluster to run without the cluster-id on cloud instances. This is a legacy mode of operation and a cluster-id will be required in the future.")
|
||||
fs.MarkDeprecated("allow-untagged-cloud", "This flag is deprecated and will be removed in a future release. A cluster-id will be required on cloud instances.")
|
||||
fs.DurationVar(&o.RouteReconciliationPeriod.Duration, "route-reconciliation-period", o.RouteReconciliationPeriod.Duration, "The period for reconciling routes created for Nodes by cloud provider.")
|
||||
fs.DurationVar(&o.NodeMonitorPeriod.Duration, "node-monitor-period", o.NodeMonitorPeriod.Duration,
|
||||
"The period for syncing NodeStatus in NodeController.")
|
||||
fmt.Sprintf("The period for syncing NodeStatus in %s.", names.CloudNodeLifecycleController))
|
||||
fs.StringVar(&o.ClusterName, "cluster-name", o.ClusterName, "The instance prefix for the cluster.")
|
||||
fs.StringVar(&o.ClusterCIDR, "cluster-cidr", o.ClusterCIDR, "CIDR Range for Pods in cluster. Requires --allocate-node-cidrs to be true")
|
||||
fs.BoolVar(&o.AllocateNodeCIDRs, "allocate-node-cidrs", false, "Should CIDRs for Pods be allocated and set on the cloud provider.")
|
||||
|
@@ -38,6 +38,7 @@ import (
|
||||
ccmconfig "k8s.io/cloud-provider/config"
|
||||
ccmconfigscheme "k8s.io/cloud-provider/config/install"
|
||||
ccmconfigv1alpha1 "k8s.io/cloud-provider/config/v1alpha1"
|
||||
"k8s.io/cloud-provider/names"
|
||||
cliflag "k8s.io/component-base/cli/flag"
|
||||
cmoptions "k8s.io/controller-manager/options"
|
||||
"k8s.io/controller-manager/pkg/clientbuilder"
|
||||
@@ -141,12 +142,12 @@ func NewDefaultComponentConfig() (*ccmconfig.CloudControllerManagerConfiguration
|
||||
}
|
||||
|
||||
// Flags returns flags for a specific CloudController by section name
|
||||
func (o *CloudControllerManagerOptions) Flags(allControllers, disabledByDefaultControllers, allWebhooks, disabledByDefaultWebhooks []string) cliflag.NamedFlagSets {
|
||||
func (o *CloudControllerManagerOptions) Flags(allControllers []string, disabledByDefaultControllers []string, controllerAliases map[string]string, allWebhooks, disabledByDefaultWebhooks []string) cliflag.NamedFlagSets {
|
||||
fss := cliflag.NamedFlagSets{}
|
||||
o.Generic.AddFlags(&fss, allControllers, disabledByDefaultControllers)
|
||||
o.Generic.AddFlags(&fss, allControllers, disabledByDefaultControllers, controllerAliases)
|
||||
o.KubeCloudShared.AddFlags(fss.FlagSet("generic"))
|
||||
o.NodeController.AddFlags(fss.FlagSet("node controller"))
|
||||
o.ServiceController.AddFlags(fss.FlagSet("service controller"))
|
||||
o.NodeController.AddFlags(fss.FlagSet(names.CloudNodeController))
|
||||
o.ServiceController.AddFlags(fss.FlagSet(names.ServiceLBController))
|
||||
if o.Webhook != nil {
|
||||
o.Webhook.AddFlags(fss.FlagSet("webhook"), allWebhooks, disabledByDefaultWebhooks)
|
||||
}
|
||||
@@ -168,7 +169,7 @@ func (o *CloudControllerManagerOptions) Flags(allControllers, disabledByDefaultC
|
||||
}
|
||||
|
||||
// ApplyTo fills up cloud controller manager config with options.
|
||||
func (o *CloudControllerManagerOptions) ApplyTo(c *config.Config, userAgent string) error {
|
||||
func (o *CloudControllerManagerOptions) ApplyTo(c *config.Config, allControllers []string, disabledByDefaultControllers []string, controllerAliases map[string]string, userAgent string) error {
|
||||
var err error
|
||||
|
||||
// Build kubeconfig first to so that if it fails, it doesn't cause leaking
|
||||
@@ -184,7 +185,7 @@ func (o *CloudControllerManagerOptions) ApplyTo(c *config.Config, userAgent stri
|
||||
c.Kubeconfig.QPS = o.Generic.ClientConnection.QPS
|
||||
c.Kubeconfig.Burst = int(o.Generic.ClientConnection.Burst)
|
||||
|
||||
if err = o.Generic.ApplyTo(&c.ComponentConfig.Generic); err != nil {
|
||||
if err = o.Generic.ApplyTo(&c.ComponentConfig.Generic, allControllers, disabledByDefaultControllers, controllerAliases); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = o.KubeCloudShared.ApplyTo(&c.ComponentConfig.KubeCloudShared); err != nil {
|
||||
@@ -246,10 +247,10 @@ func (o *CloudControllerManagerOptions) ApplyTo(c *config.Config, userAgent stri
|
||||
}
|
||||
|
||||
// Validate is used to validate config before launching the cloud controller manager
|
||||
func (o *CloudControllerManagerOptions) Validate(allControllers, disabledByDefaultControllers, allWebhooks, disabledByDefaultWebhooks []string) error {
|
||||
func (o *CloudControllerManagerOptions) Validate(allControllers []string, disabledByDefaultControllers []string, controllerAliases map[string]string, allWebhooks, disabledByDefaultWebhooks []string) error {
|
||||
errors := []error{}
|
||||
|
||||
errors = append(errors, o.Generic.Validate(allControllers, disabledByDefaultControllers)...)
|
||||
errors = append(errors, o.Generic.Validate(allControllers, disabledByDefaultControllers, controllerAliases)...)
|
||||
errors = append(errors, o.KubeCloudShared.Validate()...)
|
||||
errors = append(errors, o.ServiceController.Validate()...)
|
||||
errors = append(errors, o.SecureServing.Validate()...)
|
||||
@@ -282,8 +283,8 @@ func resyncPeriod(c *config.Config) func() time.Duration {
|
||||
}
|
||||
|
||||
// Config return a cloud controller manager config objective
|
||||
func (o *CloudControllerManagerOptions) Config(allControllers, disabledByDefaultControllers, allWebhooks, disabledByDefaultWebhooks []string) (*config.Config, error) {
|
||||
if err := o.Validate(allControllers, disabledByDefaultControllers, allWebhooks, disabledByDefaultWebhooks); err != nil {
|
||||
func (o *CloudControllerManagerOptions) Config(allControllers []string, disabledByDefaultControllers []string, controllerAliases map[string]string, allWebhooks, disabledByDefaultWebhooks []string) (*config.Config, error) {
|
||||
if err := o.Validate(allControllers, disabledByDefaultControllers, controllerAliases, allWebhooks, disabledByDefaultWebhooks); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -298,7 +299,7 @@ func (o *CloudControllerManagerOptions) Config(allControllers, disabledByDefault
|
||||
}
|
||||
|
||||
c := &config.Config{}
|
||||
if err := o.ApplyTo(c, CloudControllerManagerUserAgent); err != nil {
|
||||
if err := o.ApplyTo(c, allControllers, disabledByDefaultControllers, controllerAliases, CloudControllerManagerUserAgent); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@@ -162,7 +162,7 @@ func TestAddFlags(t *testing.T) {
|
||||
t.Errorf("unexpected err: %v", err)
|
||||
}
|
||||
|
||||
for _, f := range s.Flags([]string{""}, []string{""}, []string{""}, []string{""}).FlagSets {
|
||||
for _, f := range s.Flags([]string{""}, []string{""}, nil, []string{""}, []string{""}).FlagSets {
|
||||
fs.AddFlagSet(f)
|
||||
}
|
||||
|
||||
@@ -321,7 +321,7 @@ func TestCreateConfig(t *testing.T) {
|
||||
t.Errorf("unexpected err: %v", err)
|
||||
}
|
||||
|
||||
for _, f := range s.Flags([]string{""}, []string{""}, []string{""}, []string{""}).FlagSets {
|
||||
for _, f := range s.Flags([]string{""}, []string{""}, nil, []string{""}, []string{""}).FlagSets {
|
||||
fs.AddFlagSet(f)
|
||||
}
|
||||
|
||||
@@ -371,7 +371,7 @@ func TestCreateConfig(t *testing.T) {
|
||||
fmt.Printf("%s: %s\n", f.Name, f.Value)
|
||||
})
|
||||
|
||||
c, err := s.Config([]string{"foo", "bar"}, []string{}, []string{"foo", "bar", "baz"}, []string{})
|
||||
c, err := s.Config([]string{"foo", "bar"}, []string{}, nil, []string{"foo", "bar", "baz"}, []string{})
|
||||
assert.Nil(t, err, "unexpected error: %s", err)
|
||||
|
||||
expected := &appconfig.Config{
|
||||
@@ -447,3 +447,39 @@ func TestCreateConfig(t *testing.T) {
|
||||
t.Errorf("Got different config than expected.\nDifference detected on:\n%s", cmp.Diff(expected, c))
|
||||
}
|
||||
}
|
||||
|
||||
func TestCloudControllerManagerAliases(t *testing.T) {
|
||||
opts, err := NewCloudControllerManagerOptions()
|
||||
if err != nil {
|
||||
t.Errorf("expected no error, error found %+v", err)
|
||||
}
|
||||
opts.KubeCloudShared.CloudProvider.Name = "gce"
|
||||
opts.Generic.Controllers = []string{"service-controller", "-service", "route", "-cloud-node-lifecycle-controller"}
|
||||
expectedControllers := []string{"service-controller", "-service-controller", "route-controller", "-cloud-node-lifecycle-controller"}
|
||||
|
||||
allControllers := []string{
|
||||
"cloud-node-controller",
|
||||
"service-controller",
|
||||
"route-controller",
|
||||
"cloud-node-lifecycle-controller",
|
||||
}
|
||||
disabledByDefaultControllers := []string{}
|
||||
controllerAliases := map[string]string{
|
||||
"cloud-node": "cloud-node-controller",
|
||||
"service": "service-controller",
|
||||
"route": "route-controller",
|
||||
"cloud-node-lifecycle": "cloud-node-lifecycle-controller",
|
||||
}
|
||||
|
||||
if err := opts.Validate(allControllers, disabledByDefaultControllers, controllerAliases, nil, nil); err != nil {
|
||||
t.Errorf("expected no error, error found %v", err)
|
||||
}
|
||||
|
||||
cfg := &cmconfig.GenericControllerManagerConfiguration{}
|
||||
if err := opts.Generic.ApplyTo(cfg, allControllers, disabledByDefaultControllers, controllerAliases); err != nil {
|
||||
t.Errorf("expected no error, error found %v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(cfg.Controllers, expectedControllers) {
|
||||
t.Errorf("controller aliases not resolved correctly, expected %+v, got %+v", expectedControllers, cfg.Controllers)
|
||||
}
|
||||
}
|
||||
|
@@ -27,6 +27,7 @@ import (
|
||||
cloudprovider "k8s.io/cloud-provider"
|
||||
"k8s.io/cloud-provider/app"
|
||||
"k8s.io/cloud-provider/app/config"
|
||||
"k8s.io/cloud-provider/names"
|
||||
"k8s.io/cloud-provider/options"
|
||||
"k8s.io/component-base/cli"
|
||||
cliflag "k8s.io/component-base/cli/flag"
|
||||
@@ -45,7 +46,7 @@ func main() {
|
||||
}
|
||||
|
||||
fss := cliflag.NamedFlagSets{}
|
||||
command := app.NewCloudControllerManagerCommand(ccmOptions, cloudInitializer, controllerInitializers(), fss, wait.NeverStop)
|
||||
command := app.NewCloudControllerManagerCommand(ccmOptions, cloudInitializer, controllerInitializers(), names.CCMControllerAliases(), fss, wait.NeverStop)
|
||||
code := cli.Run(command)
|
||||
os.Exit(code)
|
||||
}
|
||||
@@ -55,21 +56,21 @@ func main() {
|
||||
// separately.
|
||||
func controllerInitializers() map[string]app.ControllerInitFuncConstructor {
|
||||
controllerInitializers := app.DefaultInitFuncConstructors
|
||||
if constructor, ok := controllerInitializers["cloud-node"]; ok {
|
||||
if constructor, ok := controllerInitializers[names.CloudNodeController]; ok {
|
||||
constructor.InitContext.ClientName = "mycloud-external-cloud-node-controller"
|
||||
controllerInitializers["cloud-node"] = constructor
|
||||
controllerInitializers[names.CloudNodeController] = constructor
|
||||
}
|
||||
if constructor, ok := controllerInitializers["cloud-node-lifecycle"]; ok {
|
||||
if constructor, ok := controllerInitializers[names.CloudNodeLifecycleController]; ok {
|
||||
constructor.InitContext.ClientName = "mycloud-external-cloud-node-lifecycle-controller"
|
||||
controllerInitializers["cloud-node-lifecycle"] = constructor
|
||||
controllerInitializers[names.CloudNodeLifecycleController] = constructor
|
||||
}
|
||||
if constructor, ok := controllerInitializers["service"]; ok {
|
||||
if constructor, ok := controllerInitializers[names.ServiceLBController]; ok {
|
||||
constructor.InitContext.ClientName = "mycloud-external-service-controller"
|
||||
controllerInitializers["service"] = constructor
|
||||
controllerInitializers[names.ServiceLBController] = constructor
|
||||
}
|
||||
if constructor, ok := controllerInitializers["route"]; ok {
|
||||
if constructor, ok := controllerInitializers[names.NodeRouteController]; ok {
|
||||
constructor.InitContext.ClientName = "mycloud-external-route-controller"
|
||||
controllerInitializers["route"] = constructor
|
||||
controllerInitializers[names.NodeRouteController] = constructor
|
||||
}
|
||||
return controllerInitializers
|
||||
}
|
||||
|
@@ -49,7 +49,7 @@ func NewGenericControllerManagerConfigurationOptions(cfg *cmconfig.GenericContro
|
||||
}
|
||||
|
||||
// AddFlags adds flags related to generic for controller manager to the specified FlagSet.
|
||||
func (o *GenericControllerManagerConfigurationOptions) AddFlags(fss *cliflag.NamedFlagSets, allControllers, disabledByDefaultControllers []string) {
|
||||
func (o *GenericControllerManagerConfigurationOptions) AddFlags(fss *cliflag.NamedFlagSets, allControllers, disabledByDefaultControllers []string, controllerAliases map[string]string) {
|
||||
if o == nil {
|
||||
return
|
||||
}
|
||||
@@ -71,7 +71,7 @@ func (o *GenericControllerManagerConfigurationOptions) AddFlags(fss *cliflag.Nam
|
||||
}
|
||||
|
||||
// ApplyTo fills up generic config with options.
|
||||
func (o *GenericControllerManagerConfigurationOptions) ApplyTo(cfg *cmconfig.GenericControllerManagerConfiguration) error {
|
||||
func (o *GenericControllerManagerConfigurationOptions) ApplyTo(cfg *cmconfig.GenericControllerManagerConfiguration, allControllers []string, disabledByDefaultControllers []string, controllerAliases map[string]string) error {
|
||||
if o == nil {
|
||||
return nil
|
||||
}
|
||||
@@ -88,13 +88,26 @@ func (o *GenericControllerManagerConfigurationOptions) ApplyTo(cfg *cmconfig.Gen
|
||||
cfg.ClientConnection = o.ClientConnection
|
||||
cfg.ControllerStartInterval = o.ControllerStartInterval
|
||||
cfg.LeaderElection = o.LeaderElection
|
||||
cfg.Controllers = o.Controllers
|
||||
|
||||
// copy controller names and replace aliases with canonical names
|
||||
cfg.Controllers = make([]string, len(o.Controllers))
|
||||
for i, initialName := range o.Controllers {
|
||||
initialNameWithoutPrefix := strings.TrimPrefix(initialName, "-")
|
||||
controllerName := initialNameWithoutPrefix
|
||||
if canonicalName, ok := controllerAliases[controllerName]; ok {
|
||||
controllerName = canonicalName
|
||||
}
|
||||
if strings.HasPrefix(initialName, "-") {
|
||||
controllerName = fmt.Sprintf("-%s", controllerName)
|
||||
}
|
||||
cfg.Controllers[i] = controllerName
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate checks validation of GenericOptions.
|
||||
func (o *GenericControllerManagerConfigurationOptions) Validate(allControllers []string, disabledByDefaultControllers []string) []error {
|
||||
func (o *GenericControllerManagerConfigurationOptions) Validate(allControllers []string, disabledByDefaultControllers []string, controllerAliases map[string]string) []error {
|
||||
if o == nil {
|
||||
return nil
|
||||
}
|
||||
@@ -109,13 +122,17 @@ func (o *GenericControllerManagerConfigurationOptions) Validate(allControllers [
|
||||
}
|
||||
|
||||
allControllersSet := sets.NewString(allControllers...)
|
||||
for _, controller := range o.Controllers {
|
||||
if controller == "*" {
|
||||
for _, initialName := range o.Controllers {
|
||||
if initialName == "*" {
|
||||
continue
|
||||
}
|
||||
controller = strings.TrimPrefix(controller, "-")
|
||||
if !allControllersSet.Has(controller) {
|
||||
errs = append(errs, fmt.Errorf("%q is not in the list of known controllers", controller))
|
||||
initialNameWithoutPrefix := strings.TrimPrefix(initialName, "-")
|
||||
controllerName := initialNameWithoutPrefix
|
||||
if canonicalName, ok := controllerAliases[controllerName]; ok {
|
||||
controllerName = canonicalName
|
||||
}
|
||||
if !allControllersSet.Has(controllerName) {
|
||||
errs = append(errs, fmt.Errorf("%q is not in the list of known controllers", initialNameWithoutPrefix))
|
||||
}
|
||||
}
|
||||
|
||||
|
260
staging/src/k8s.io/controller-manager/options/generic_test.go
Normal file
260
staging/src/k8s.io/controller-manager/options/generic_test.go
Normal file
@@ -0,0 +1,260 @@
|
||||
/*
|
||||
Copyright 2023 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package options
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||
"k8s.io/component-base/config"
|
||||
cmconfig "k8s.io/controller-manager/config"
|
||||
)
|
||||
|
||||
func TestValidateGenericControllerManagerConfigurationOptions(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
allControllers []string
|
||||
controllerAliases map[string]string
|
||||
options *GenericControllerManagerConfigurationOptions
|
||||
expectErrors bool
|
||||
expectedErrorSubString string
|
||||
}{
|
||||
{
|
||||
name: "no controllers defined",
|
||||
allControllers: nil,
|
||||
controllerAliases: nil,
|
||||
options: NewGenericControllerManagerConfigurationOptions(&cmconfig.GenericControllerManagerConfiguration{
|
||||
Controllers: []string{
|
||||
"*",
|
||||
},
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: "recognizes empty controllers",
|
||||
allControllers: getAllControllers(),
|
||||
controllerAliases: getControllerAliases(),
|
||||
options: NewGenericControllerManagerConfigurationOptions(&cmconfig.GenericControllerManagerConfiguration{}),
|
||||
},
|
||||
{
|
||||
name: "recognizes controllers without any aliases",
|
||||
allControllers: getAllControllers(),
|
||||
controllerAliases: nil,
|
||||
options: NewGenericControllerManagerConfigurationOptions(&cmconfig.GenericControllerManagerConfiguration{
|
||||
Controllers: []string{
|
||||
"blue-controller",
|
||||
},
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: "recognizes valid controllers",
|
||||
allControllers: getAllControllers(),
|
||||
controllerAliases: getControllerAliases(),
|
||||
options: NewGenericControllerManagerConfigurationOptions(&cmconfig.GenericControllerManagerConfiguration{
|
||||
Controllers: []string{
|
||||
"*",
|
||||
"-red-controller",
|
||||
"blue-controller",
|
||||
},
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: "recognizes disabled controller",
|
||||
allControllers: getAllControllers(),
|
||||
controllerAliases: getControllerAliases(),
|
||||
options: NewGenericControllerManagerConfigurationOptions(&cmconfig.GenericControllerManagerConfiguration{
|
||||
Controllers: []string{
|
||||
"green-controller",
|
||||
},
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: "recognized aliased controller",
|
||||
allControllers: getAllControllers(),
|
||||
controllerAliases: getControllerAliases(),
|
||||
options: NewGenericControllerManagerConfigurationOptions(&cmconfig.GenericControllerManagerConfiguration{
|
||||
Controllers: []string{
|
||||
"ultramarine-controller",
|
||||
"-pink-controller",
|
||||
},
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: "does not recognize controller",
|
||||
allControllers: nil,
|
||||
controllerAliases: nil,
|
||||
options: NewGenericControllerManagerConfigurationOptions(&cmconfig.GenericControllerManagerConfiguration{
|
||||
Controllers: []string{
|
||||
"red-controller",
|
||||
},
|
||||
}),
|
||||
expectErrors: true,
|
||||
expectedErrorSubString: "\"red-controller\" is not in the list of known controllers",
|
||||
},
|
||||
{
|
||||
name: "does not recognize controller with aliases",
|
||||
allControllers: getAllControllers(),
|
||||
controllerAliases: getControllerAliases(),
|
||||
options: NewGenericControllerManagerConfigurationOptions(&cmconfig.GenericControllerManagerConfiguration{
|
||||
Controllers: []string{
|
||||
"crimson-controller",
|
||||
"grey-controller",
|
||||
},
|
||||
}),
|
||||
expectErrors: true,
|
||||
expectedErrorSubString: "\"grey-controller\" is not in the list of known controllers",
|
||||
},
|
||||
{
|
||||
name: "leader election accepts only leases",
|
||||
allControllers: getAllControllers(),
|
||||
controllerAliases: getControllerAliases(),
|
||||
options: NewGenericControllerManagerConfigurationOptions(&cmconfig.GenericControllerManagerConfiguration{
|
||||
LeaderElection: config.LeaderElectionConfiguration{
|
||||
LeaderElect: true,
|
||||
ResourceLock: "configmapsleases",
|
||||
},
|
||||
}),
|
||||
expectErrors: true,
|
||||
expectedErrorSubString: "resourceLock value must be \"leases\"",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
errs := tc.options.Validate(tc.allControllers, []string{"green-controller"}, tc.controllerAliases)
|
||||
if len(errs) > 0 && !tc.expectErrors {
|
||||
t.Errorf("expected no errors, errors found %+v", errs)
|
||||
}
|
||||
|
||||
if len(errs) == 0 && tc.expectErrors {
|
||||
t.Errorf("expected errors, no errors found")
|
||||
}
|
||||
|
||||
if len(errs) > 0 && tc.expectErrors {
|
||||
gotErr := utilerrors.NewAggregate(errs).Error()
|
||||
if !strings.Contains(gotErr, tc.expectedErrorSubString) {
|
||||
t.Errorf("expected error: %s, got err: %v", tc.expectedErrorSubString, gotErr)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyToGenericControllerManagerConfigurationOptions(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
allControllers []string
|
||||
controllerAliases map[string]string
|
||||
options *GenericControllerManagerConfigurationOptions
|
||||
expectedControllers []string
|
||||
}{
|
||||
{
|
||||
name: "no controllers defined",
|
||||
allControllers: nil,
|
||||
controllerAliases: nil,
|
||||
options: NewGenericControllerManagerConfigurationOptions(&cmconfig.GenericControllerManagerConfiguration{
|
||||
Controllers: []string{
|
||||
"*",
|
||||
},
|
||||
}),
|
||||
expectedControllers: []string{
|
||||
"*",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "empty aliases",
|
||||
allControllers: getAllControllers(),
|
||||
controllerAliases: nil,
|
||||
options: NewGenericControllerManagerConfigurationOptions(&cmconfig.GenericControllerManagerConfiguration{
|
||||
Controllers: []string{
|
||||
"-blue-controller",
|
||||
},
|
||||
}),
|
||||
expectedControllers: []string{
|
||||
"-blue-controller",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "applies valid controllers",
|
||||
allControllers: getAllControllers(),
|
||||
controllerAliases: getControllerAliases(),
|
||||
options: NewGenericControllerManagerConfigurationOptions(&cmconfig.GenericControllerManagerConfiguration{
|
||||
Controllers: []string{
|
||||
"*",
|
||||
"green-controller",
|
||||
"-red-controller",
|
||||
"blue-controller",
|
||||
},
|
||||
}),
|
||||
expectedControllers: []string{
|
||||
"*",
|
||||
"green-controller",
|
||||
"-red-controller",
|
||||
"blue-controller",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "resolves aliases",
|
||||
allControllers: getAllControllers(),
|
||||
controllerAliases: getControllerAliases(),
|
||||
options: NewGenericControllerManagerConfigurationOptions(&cmconfig.GenericControllerManagerConfiguration{
|
||||
Controllers: []string{
|
||||
"green-controller",
|
||||
"-crimson-controller",
|
||||
"ultramarine-controller",
|
||||
"-pink-controller",
|
||||
},
|
||||
}),
|
||||
expectedControllers: []string{
|
||||
"green-controller",
|
||||
"-red-controller",
|
||||
"blue-controller",
|
||||
"-red-controller",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
cfg := &cmconfig.GenericControllerManagerConfiguration{}
|
||||
err := tc.options.ApplyTo(cfg, tc.allControllers, []string{"green-controller"}, tc.controllerAliases)
|
||||
if err != nil {
|
||||
t.Errorf("expected no errors, error found: %v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(cfg.Controllers, tc.expectedControllers) {
|
||||
t.Errorf("applyTo failed, expected controllers %q, got controllers %q", strings.Join(cfg.Controllers, ","), strings.Join(tc.expectedControllers, ","))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func getAllControllers() []string {
|
||||
return []string{
|
||||
"red-controller",
|
||||
"green-controller",
|
||||
"blue-controller",
|
||||
}
|
||||
}
|
||||
|
||||
func getControllerAliases() map[string]string {
|
||||
return map[string]string{
|
||||
"crimson-controller": "red-controller",
|
||||
"pink-controller": "red-controller",
|
||||
"ultramarine-controller": "blue-controller",
|
||||
}
|
||||
}
|
@@ -26,13 +26,13 @@ func DefaultLeaderMigrationConfiguration() *internal.LeaderMigrationConfiguratio
|
||||
ResourceLock: ResourceLockLeases,
|
||||
ControllerLeaders: []internal.ControllerLeaderConfiguration{
|
||||
{
|
||||
Name: "route",
|
||||
Name: "route-controller",
|
||||
Component: "*",
|
||||
}, {
|
||||
Name: "service",
|
||||
Name: "service-controller",
|
||||
Component: "*",
|
||||
}, {
|
||||
Name: "cloud-node-lifecycle",
|
||||
Name: "cloud-node-lifecycle-controller",
|
||||
Component: "*",
|
||||
},
|
||||
},
|
||||
|
@@ -28,13 +28,13 @@ func TestLeaderMigratorFilterFunc(t *testing.T) {
|
||||
LeaderName: "cloud-provider-extraction-migration",
|
||||
ControllerLeaders: []internal.ControllerLeaderConfiguration{
|
||||
{
|
||||
Name: "route",
|
||||
Name: "route-controller",
|
||||
Component: "kube-controller-manager",
|
||||
}, {
|
||||
Name: "service",
|
||||
Name: "service-controller",
|
||||
Component: "kube-controller-manager",
|
||||
}, {
|
||||
Name: "cloud-node-lifecycle",
|
||||
Name: "cloud-node-lifecycle-controller",
|
||||
Component: "kube-controller-manager",
|
||||
},
|
||||
},
|
||||
@@ -44,13 +44,13 @@ func TestLeaderMigratorFilterFunc(t *testing.T) {
|
||||
LeaderName: "cloud-provider-extraction-migration",
|
||||
ControllerLeaders: []internal.ControllerLeaderConfiguration{
|
||||
{
|
||||
Name: "route",
|
||||
Name: "route-controller",
|
||||
Component: "cloud-controller-manager",
|
||||
}, {
|
||||
Name: "service",
|
||||
Name: "service-controller",
|
||||
Component: "cloud-controller-manager",
|
||||
}, {
|
||||
Name: "cloud-node-lifecycle",
|
||||
Name: "cloud-node-lifecycle-controller",
|
||||
Component: "cloud-controller-manager",
|
||||
},
|
||||
},
|
||||
@@ -60,13 +60,13 @@ func TestLeaderMigratorFilterFunc(t *testing.T) {
|
||||
LeaderName: "cloud-provider-extraction-migration",
|
||||
ControllerLeaders: []internal.ControllerLeaderConfiguration{
|
||||
{
|
||||
Name: "route",
|
||||
Name: "route-controller",
|
||||
Component: "*",
|
||||
}, {
|
||||
Name: "service",
|
||||
Name: "service-controller",
|
||||
Component: "*",
|
||||
}, {
|
||||
Name: "cloud-node-lifecycle",
|
||||
Name: "cloud-node-lifecycle-controller",
|
||||
Component: "*",
|
||||
},
|
||||
},
|
||||
@@ -83,10 +83,10 @@ func TestLeaderMigratorFilterFunc(t *testing.T) {
|
||||
config: fromConfig,
|
||||
component: "kube-controller-manager",
|
||||
expectResult: map[string]FilterResult{
|
||||
"deployment": ControllerNonMigrated,
|
||||
"route": ControllerMigrated,
|
||||
"service": ControllerMigrated,
|
||||
"cloud-node-lifecycle": ControllerMigrated,
|
||||
"deployment-controller": ControllerNonMigrated,
|
||||
"route-controller": ControllerMigrated,
|
||||
"service-controller": ControllerMigrated,
|
||||
"cloud-node-lifecycle-controller": ControllerMigrated,
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -95,9 +95,9 @@ func TestLeaderMigratorFilterFunc(t *testing.T) {
|
||||
component: "cloud-controller-manager",
|
||||
expectResult: map[string]FilterResult{
|
||||
"cloud-node": ControllerNonMigrated,
|
||||
"route": ControllerUnowned,
|
||||
"service": ControllerUnowned,
|
||||
"cloud-node-lifecycle": ControllerUnowned,
|
||||
"route-controller": ControllerUnowned,
|
||||
"service-controller": ControllerUnowned,
|
||||
"cloud-node-lifecycle-controller": ControllerUnowned,
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -105,10 +105,10 @@ func TestLeaderMigratorFilterFunc(t *testing.T) {
|
||||
config: toConfig,
|
||||
component: "kube-controller-manager",
|
||||
expectResult: map[string]FilterResult{
|
||||
"deployment": ControllerNonMigrated,
|
||||
"route": ControllerUnowned,
|
||||
"service": ControllerUnowned,
|
||||
"cloud-node-lifecycle": ControllerUnowned,
|
||||
"deployment-controller": ControllerNonMigrated,
|
||||
"route-controller": ControllerUnowned,
|
||||
"service-controller": ControllerUnowned,
|
||||
"cloud-node-lifecycle-controller": ControllerUnowned,
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -116,10 +116,10 @@ func TestLeaderMigratorFilterFunc(t *testing.T) {
|
||||
config: toConfig,
|
||||
component: "cloud-controller-manager",
|
||||
expectResult: map[string]FilterResult{
|
||||
"cloud-node": ControllerNonMigrated,
|
||||
"route": ControllerMigrated,
|
||||
"service": ControllerMigrated,
|
||||
"cloud-node-lifecycle": ControllerMigrated,
|
||||
"cloud-node-controller": ControllerNonMigrated,
|
||||
"route-controller": ControllerMigrated,
|
||||
"service-controller": ControllerMigrated,
|
||||
"cloud-node-lifecycle-controller": ControllerMigrated,
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -127,10 +127,10 @@ func TestLeaderMigratorFilterFunc(t *testing.T) {
|
||||
config: wildcardConfig,
|
||||
component: "kube-controller-manager",
|
||||
expectResult: map[string]FilterResult{
|
||||
"deployment": ControllerNonMigrated, // KCM only
|
||||
"route": ControllerMigrated,
|
||||
"service": ControllerMigrated,
|
||||
"cloud-node-lifecycle": ControllerMigrated,
|
||||
"deployment-controller": ControllerNonMigrated, // KCM only
|
||||
"route-controller": ControllerMigrated,
|
||||
"service-controller": ControllerMigrated,
|
||||
"cloud-node-lifecycle-controller": ControllerMigrated,
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -138,10 +138,10 @@ func TestLeaderMigratorFilterFunc(t *testing.T) {
|
||||
config: wildcardConfig,
|
||||
component: "cloud-controller-manager",
|
||||
expectResult: map[string]FilterResult{
|
||||
"cloud-node": ControllerNonMigrated, // CCM only
|
||||
"route": ControllerMigrated,
|
||||
"service": ControllerMigrated,
|
||||
"cloud-node-lifecycle": ControllerMigrated,
|
||||
"cloud-node-controller": ControllerNonMigrated, // CCM only
|
||||
"route-controller": ControllerMigrated,
|
||||
"service-controller": ControllerMigrated,
|
||||
"cloud-node-lifecycle-controller": ControllerMigrated,
|
||||
},
|
||||
},
|
||||
} {
|
||||
|
@@ -107,13 +107,13 @@ apiVersion: controllermanager.config.k8s.io/v1
|
||||
kind: LeaderMigrationConfiguration
|
||||
leaderName: test-leader-migration
|
||||
controllerLeaders:
|
||||
- name: route
|
||||
- name: route-controller
|
||||
component: "*"
|
||||
- name: service
|
||||
- name: service-controller
|
||||
component: "*"
|
||||
- name: cloud-node-lifecycle
|
||||
- name: cloud-node-lifecycle-controller
|
||||
component: "*"
|
||||
- name: nodeipam
|
||||
- name: node-ipam-controller
|
||||
component: "*"
|
||||
`,
|
||||
expectErr: false,
|
||||
@@ -122,19 +122,19 @@ controllerLeaders:
|
||||
ResourceLock: "leases",
|
||||
ControllerLeaders: []config.ControllerLeaderConfiguration{
|
||||
{
|
||||
Name: "route",
|
||||
Name: "route-controller",
|
||||
Component: "*",
|
||||
},
|
||||
{
|
||||
Name: "service",
|
||||
Name: "service-controller",
|
||||
Component: "*",
|
||||
},
|
||||
{
|
||||
Name: "cloud-node-lifecycle",
|
||||
Name: "cloud-node-lifecycle-controller",
|
||||
Component: "*",
|
||||
},
|
||||
{
|
||||
Name: "nodeipam",
|
||||
Name: "node-ipam-controller",
|
||||
Component: "*",
|
||||
},
|
||||
},
|
||||
@@ -148,13 +148,13 @@ apiVersion: controllermanager.config.k8s.io/v1
|
||||
kind: LeaderMigrationConfiguration
|
||||
leaderName: test-leader-migration
|
||||
controllerLeaders:
|
||||
- name: route
|
||||
- name: route-controller
|
||||
component: "cloud-controller-manager"
|
||||
- name: service
|
||||
- name: service-controller
|
||||
component: "cloud-controller-manager"
|
||||
- name: cloud-node-lifecycle
|
||||
- name: cloud-node-lifecycle-controller
|
||||
component: "cloud-controller-manager"
|
||||
- name: nodeipam
|
||||
- name: node-ipam-controller
|
||||
component: "kube-controller-manager"
|
||||
`,
|
||||
expectErr: false,
|
||||
@@ -163,19 +163,19 @@ controllerLeaders:
|
||||
ResourceLock: "leases",
|
||||
ControllerLeaders: []config.ControllerLeaderConfiguration{
|
||||
{
|
||||
Name: "route",
|
||||
Name: "route-controller",
|
||||
Component: "cloud-controller-manager",
|
||||
},
|
||||
{
|
||||
Name: "service",
|
||||
Name: "service-controller",
|
||||
Component: "cloud-controller-manager",
|
||||
},
|
||||
{
|
||||
Name: "cloud-node-lifecycle",
|
||||
Name: "cloud-node-lifecycle-controller",
|
||||
Component: "cloud-controller-manager",
|
||||
},
|
||||
{
|
||||
Name: "nodeipam",
|
||||
Name: "node-ipam-controller",
|
||||
Component: "kube-controller-manager",
|
||||
},
|
||||
},
|
||||
|
1
vendor/modules.txt
vendored
1
vendor/modules.txt
vendored
@@ -1953,6 +1953,7 @@ k8s.io/cloud-provider/controllers/service/config
|
||||
k8s.io/cloud-provider/controllers/service/config/v1alpha1
|
||||
k8s.io/cloud-provider/credentialconfig
|
||||
k8s.io/cloud-provider/fake
|
||||
k8s.io/cloud-provider/names
|
||||
k8s.io/cloud-provider/node/helpers
|
||||
k8s.io/cloud-provider/options
|
||||
k8s.io/cloud-provider/service/helpers
|
||||
|
Reference in New Issue
Block a user