k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/cmd/kube-controller-manager/app/core.go (about)

     1  /*
     2  Copyright 2016 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  // Package app implements a server that runs a set of active
    18  // components.  This includes replication controllers, service endpoints and
    19  // nodes.
    20  package app
    21  
    22  import (
    23  	"context"
    24  	"errors"
    25  	"fmt"
    26  	"net"
    27  	"strings"
    28  	"time"
    29  
    30  	"k8s.io/klog/v2"
    31  
    32  	v1 "k8s.io/api/core/v1"
    33  	"k8s.io/apimachinery/pkg/runtime/schema"
    34  	genericfeatures "k8s.io/apiserver/pkg/features"
    35  	"k8s.io/apiserver/pkg/quota/v1/generic"
    36  	utilfeature "k8s.io/apiserver/pkg/util/feature"
    37  	clientset "k8s.io/client-go/kubernetes"
    38  	"k8s.io/client-go/metadata"
    39  	restclient "k8s.io/client-go/rest"
    40  	cloudnodelifecyclecontroller "k8s.io/cloud-provider/controllers/nodelifecycle"
    41  	routecontroller "k8s.io/cloud-provider/controllers/route"
    42  	servicecontroller "k8s.io/cloud-provider/controllers/service"
    43  	cpnames "k8s.io/cloud-provider/names"
    44  	"k8s.io/component-base/featuregate"
    45  	"k8s.io/controller-manager/controller"
    46  	csitrans "k8s.io/csi-translation-lib"
    47  	"k8s.io/kubernetes/cmd/kube-controller-manager/names"
    48  	pkgcontroller "k8s.io/kubernetes/pkg/controller"
    49  	endpointcontroller "k8s.io/kubernetes/pkg/controller/endpoint"
    50  	"k8s.io/kubernetes/pkg/controller/garbagecollector"
    51  	namespacecontroller "k8s.io/kubernetes/pkg/controller/namespace"
    52  	nodeipamcontroller "k8s.io/kubernetes/pkg/controller/nodeipam"
    53  	nodeipamconfig "k8s.io/kubernetes/pkg/controller/nodeipam/config"
    54  	"k8s.io/kubernetes/pkg/controller/nodeipam/ipam"
    55  	lifecyclecontroller "k8s.io/kubernetes/pkg/controller/nodelifecycle"
    56  	"k8s.io/kubernetes/pkg/controller/podgc"
    57  	replicationcontroller "k8s.io/kubernetes/pkg/controller/replication"
    58  	"k8s.io/kubernetes/pkg/controller/resourceclaim"
    59  	resourcequotacontroller "k8s.io/kubernetes/pkg/controller/resourcequota"
    60  	serviceaccountcontroller "k8s.io/kubernetes/pkg/controller/serviceaccount"
    61  	"k8s.io/kubernetes/pkg/controller/storageversiongc"
    62  	"k8s.io/kubernetes/pkg/controller/tainteviction"
    63  	ttlcontroller "k8s.io/kubernetes/pkg/controller/ttl"
    64  	"k8s.io/kubernetes/pkg/controller/ttlafterfinished"
    65  	"k8s.io/kubernetes/pkg/controller/volume/attachdetach"
    66  	"k8s.io/kubernetes/pkg/controller/volume/ephemeral"
    67  	"k8s.io/kubernetes/pkg/controller/volume/expand"
    68  	persistentvolumecontroller "k8s.io/kubernetes/pkg/controller/volume/persistentvolume"
    69  	"k8s.io/kubernetes/pkg/controller/volume/pvcprotection"
    70  	"k8s.io/kubernetes/pkg/controller/volume/pvprotection"
    71  	"k8s.io/kubernetes/pkg/features"
    72  	quotainstall "k8s.io/kubernetes/pkg/quota/v1/install"
    73  	"k8s.io/kubernetes/pkg/volume/csimigration"
    74  	"k8s.io/utils/clock"
    75  	netutils "k8s.io/utils/net"
    76  )
    77  
    78  const (
    79  	// defaultNodeMaskCIDRIPv4 is default mask size for IPv4 node cidr
    80  	defaultNodeMaskCIDRIPv4 = 24
    81  	// defaultNodeMaskCIDRIPv6 is default mask size for IPv6 node cidr
    82  	defaultNodeMaskCIDRIPv6 = 64
    83  )
    84  
    85  func newServiceLBControllerDescriptor() *ControllerDescriptor {
    86  	return &ControllerDescriptor{
    87  		name:                      cpnames.ServiceLBController,
    88  		aliases:                   []string{"service"},
    89  		initFunc:                  startServiceLBController,
    90  		isCloudProviderController: true,
    91  	}
    92  }
    93  
    94  func startServiceLBController(ctx context.Context, controllerContext ControllerContext, controllerName string) (controller.Interface, bool, error) {
    95  	serviceController, err := servicecontroller.New(
    96  		controllerContext.Cloud,
    97  		controllerContext.ClientBuilder.ClientOrDie("service-controller"),
    98  		controllerContext.InformerFactory.Core().V1().Services(),
    99  		controllerContext.InformerFactory.Core().V1().Nodes(),
   100  		controllerContext.ComponentConfig.KubeCloudShared.ClusterName,
   101  		utilfeature.DefaultFeatureGate,
   102  	)
   103  	if err != nil {
   104  		// This error shouldn't fail. It lives like this as a legacy.
   105  		klog.FromContext(ctx).Error(err, "Failed to start service controller")
   106  		return nil, false, nil
   107  	}
   108  	go serviceController.Run(ctx, int(controllerContext.ComponentConfig.ServiceController.ConcurrentServiceSyncs), controllerContext.ControllerManagerMetrics)
   109  	return nil, true, nil
   110  }
   111  func newNodeIpamControllerDescriptor() *ControllerDescriptor {
   112  	return &ControllerDescriptor{
   113  		name:     names.NodeIpamController,
   114  		aliases:  []string{"nodeipam"},
   115  		initFunc: startNodeIpamController,
   116  	}
   117  }
   118  
   119  func startNodeIpamController(ctx context.Context, controllerContext ControllerContext, controllerName string) (controller.Interface, bool, error) {
   120  	var serviceCIDR *net.IPNet
   121  	var secondaryServiceCIDR *net.IPNet
   122  	logger := klog.FromContext(ctx)
   123  
   124  	// should we start nodeIPAM
   125  	if !controllerContext.ComponentConfig.KubeCloudShared.AllocateNodeCIDRs {
   126  		return nil, false, nil
   127  	}
   128  
   129  	if controllerContext.ComponentConfig.KubeCloudShared.CIDRAllocatorType == string(ipam.CloudAllocatorType) {
   130  		// Cannot run cloud ipam controller if cloud provider is nil (--cloud-provider not set or set to 'external')
   131  		if controllerContext.Cloud == nil {
   132  			return nil, false, errors.New("--cidr-allocator-type is set to 'CloudAllocator' but cloud provider is not configured")
   133  		}
   134  		// As part of the removal of all the cloud providers from kubernetes, this support will be removed as well
   135  		klog.Warningf("DEPRECATED: 'CloudAllocator' bas been deprecated and will be removed in a future release.")
   136  	}
   137  
   138  	clusterCIDRs, err := validateCIDRs(controllerContext.ComponentConfig.KubeCloudShared.ClusterCIDR)
   139  	if err != nil {
   140  		return nil, false, err
   141  	}
   142  
   143  	// service cidr processing
   144  	if len(strings.TrimSpace(controllerContext.ComponentConfig.NodeIPAMController.ServiceCIDR)) != 0 {
   145  		_, serviceCIDR, err = netutils.ParseCIDRSloppy(controllerContext.ComponentConfig.NodeIPAMController.ServiceCIDR)
   146  		if err != nil {
   147  			logger.Info("Warning: unsuccessful parsing of service CIDR", "CIDR", controllerContext.ComponentConfig.NodeIPAMController.ServiceCIDR, "err", err)
   148  		}
   149  	}
   150  
   151  	if len(strings.TrimSpace(controllerContext.ComponentConfig.NodeIPAMController.SecondaryServiceCIDR)) != 0 {
   152  		_, secondaryServiceCIDR, err = netutils.ParseCIDRSloppy(controllerContext.ComponentConfig.NodeIPAMController.SecondaryServiceCIDR)
   153  		if err != nil {
   154  			logger.Info("Warning: unsuccessful parsing of service CIDR", "CIDR", controllerContext.ComponentConfig.NodeIPAMController.SecondaryServiceCIDR, "err", err)
   155  		}
   156  	}
   157  
   158  	// the following checks are triggered if both serviceCIDR and secondaryServiceCIDR are provided
   159  	if serviceCIDR != nil && secondaryServiceCIDR != nil {
   160  		// should be dual stack (from different IPFamilies)
   161  		dualstackServiceCIDR, err := netutils.IsDualStackCIDRs([]*net.IPNet{serviceCIDR, secondaryServiceCIDR})
   162  		if err != nil {
   163  			return nil, false, fmt.Errorf("failed to perform dualstack check on serviceCIDR and secondaryServiceCIDR error:%v", err)
   164  		}
   165  		if !dualstackServiceCIDR {
   166  			return nil, false, fmt.Errorf("serviceCIDR and secondaryServiceCIDR are not dualstack (from different IPfamiles)")
   167  		}
   168  	}
   169  
   170  	// only --node-cidr-mask-size-ipv4 and --node-cidr-mask-size-ipv6 supported with dual stack clusters.
   171  	// --node-cidr-mask-size flag is incompatible with dual stack clusters.
   172  	nodeCIDRMaskSizes, err := setNodeCIDRMaskSizes(controllerContext.ComponentConfig.NodeIPAMController, clusterCIDRs)
   173  	if err != nil {
   174  		return nil, false, err
   175  	}
   176  
   177  	nodeIpamController, err := nodeipamcontroller.NewNodeIpamController(
   178  		ctx,
   179  		controllerContext.InformerFactory.Core().V1().Nodes(),
   180  		controllerContext.Cloud,
   181  		controllerContext.ClientBuilder.ClientOrDie("node-controller"),
   182  		clusterCIDRs,
   183  		serviceCIDR,
   184  		secondaryServiceCIDR,
   185  		nodeCIDRMaskSizes,
   186  		ipam.CIDRAllocatorType(controllerContext.ComponentConfig.KubeCloudShared.CIDRAllocatorType),
   187  	)
   188  	if err != nil {
   189  		return nil, true, err
   190  	}
   191  	go nodeIpamController.RunWithMetrics(ctx, controllerContext.ControllerManagerMetrics)
   192  	return nil, true, nil
   193  }
   194  
   195  func newNodeLifecycleControllerDescriptor() *ControllerDescriptor {
   196  	return &ControllerDescriptor{
   197  		name:     names.NodeLifecycleController,
   198  		aliases:  []string{"nodelifecycle"},
   199  		initFunc: startNodeLifecycleController,
   200  	}
   201  }
   202  
   203  func startNodeLifecycleController(ctx context.Context, controllerContext ControllerContext, controllerName string) (controller.Interface, bool, error) {
   204  	lifecycleController, err := lifecyclecontroller.NewNodeLifecycleController(
   205  		ctx,
   206  		controllerContext.InformerFactory.Coordination().V1().Leases(),
   207  		controllerContext.InformerFactory.Core().V1().Pods(),
   208  		controllerContext.InformerFactory.Core().V1().Nodes(),
   209  		controllerContext.InformerFactory.Apps().V1().DaemonSets(),
   210  		// node lifecycle controller uses existing cluster role from node-controller
   211  		controllerContext.ClientBuilder.ClientOrDie("node-controller"),
   212  		controllerContext.ComponentConfig.KubeCloudShared.NodeMonitorPeriod.Duration,
   213  		controllerContext.ComponentConfig.NodeLifecycleController.NodeStartupGracePeriod.Duration,
   214  		controllerContext.ComponentConfig.NodeLifecycleController.NodeMonitorGracePeriod.Duration,
   215  		controllerContext.ComponentConfig.NodeLifecycleController.NodeEvictionRate,
   216  		controllerContext.ComponentConfig.NodeLifecycleController.SecondaryNodeEvictionRate,
   217  		controllerContext.ComponentConfig.NodeLifecycleController.LargeClusterSizeThreshold,
   218  		controllerContext.ComponentConfig.NodeLifecycleController.UnhealthyZoneThreshold,
   219  	)
   220  	if err != nil {
   221  		return nil, true, err
   222  	}
   223  	go lifecycleController.Run(ctx)
   224  	return nil, true, nil
   225  }
   226  
   227  func newTaintEvictionControllerDescriptor() *ControllerDescriptor {
   228  	return &ControllerDescriptor{
   229  		name:     names.TaintEvictionController,
   230  		initFunc: startTaintEvictionController,
   231  		requiredFeatureGates: []featuregate.Feature{
   232  			features.SeparateTaintEvictionController,
   233  		},
   234  	}
   235  }
   236  
   237  func startTaintEvictionController(ctx context.Context, controllerContext ControllerContext, controllerName string) (controller.Interface, bool, error) {
   238  	taintEvictionController, err := tainteviction.New(
   239  		ctx,
   240  		// taint-manager uses existing cluster role from node-controller
   241  		controllerContext.ClientBuilder.ClientOrDie("node-controller"),
   242  		controllerContext.InformerFactory.Core().V1().Pods(),
   243  		controllerContext.InformerFactory.Core().V1().Nodes(),
   244  		controllerName,
   245  	)
   246  	if err != nil {
   247  		return nil, false, err
   248  	}
   249  	go taintEvictionController.Run(ctx)
   250  	return nil, true, nil
   251  }
   252  
   253  func newCloudNodeLifecycleControllerDescriptor() *ControllerDescriptor {
   254  	return &ControllerDescriptor{
   255  		name:                      cpnames.CloudNodeLifecycleController,
   256  		aliases:                   []string{"cloud-node-lifecycle"},
   257  		initFunc:                  startCloudNodeLifecycleController,
   258  		isCloudProviderController: true,
   259  	}
   260  }
   261  
   262  func startCloudNodeLifecycleController(ctx context.Context, controllerContext ControllerContext, controllerName string) (controller.Interface, bool, error) {
   263  	logger := klog.FromContext(ctx)
   264  	cloudNodeLifecycleController, err := cloudnodelifecyclecontroller.NewCloudNodeLifecycleController(
   265  		controllerContext.InformerFactory.Core().V1().Nodes(),
   266  		// cloud node lifecycle controller uses existing cluster role from node-controller
   267  		controllerContext.ClientBuilder.ClientOrDie("node-controller"),
   268  		controllerContext.Cloud,
   269  		controllerContext.ComponentConfig.KubeCloudShared.NodeMonitorPeriod.Duration,
   270  	)
   271  	if err != nil {
   272  		// the controller manager should continue to run if the "Instances" interface is not
   273  		// supported, though it's unlikely for a cloud provider to not support it
   274  		logger.Error(err, "Failed to start cloud node lifecycle controller")
   275  		return nil, false, nil
   276  	}
   277  
   278  	go cloudNodeLifecycleController.Run(ctx, controllerContext.ControllerManagerMetrics)
   279  	return nil, true, nil
   280  }
   281  
   282  func newNodeRouteControllerDescriptor() *ControllerDescriptor {
   283  	return &ControllerDescriptor{
   284  		name:                      cpnames.NodeRouteController,
   285  		aliases:                   []string{"route"},
   286  		initFunc:                  startNodeRouteController,
   287  		isCloudProviderController: true,
   288  	}
   289  }
   290  
   291  func startNodeRouteController(ctx context.Context, controllerContext ControllerContext, controllerName string) (controller.Interface, bool, error) {
   292  	logger := klog.FromContext(ctx)
   293  	if !controllerContext.ComponentConfig.KubeCloudShared.AllocateNodeCIDRs || !controllerContext.ComponentConfig.KubeCloudShared.ConfigureCloudRoutes {
   294  		logger.Info("Will not configure cloud provider routes for allocate-node-cidrs", "CIDRs", controllerContext.ComponentConfig.KubeCloudShared.AllocateNodeCIDRs, "routes", controllerContext.ComponentConfig.KubeCloudShared.ConfigureCloudRoutes)
   295  		return nil, false, nil
   296  	}
   297  	if controllerContext.Cloud == nil {
   298  		logger.Info("Warning: configure-cloud-routes is set, but no cloud provider specified. Will not configure cloud provider routes.")
   299  		return nil, false, nil
   300  	}
   301  	routes, ok := controllerContext.Cloud.Routes()
   302  	if !ok {
   303  		logger.Info("Warning: configure-cloud-routes is set, but cloud provider does not support routes. Will not configure cloud provider routes.")
   304  		return nil, false, nil
   305  	}
   306  
   307  	clusterCIDRs, err := validateCIDRs(controllerContext.ComponentConfig.KubeCloudShared.ClusterCIDR)
   308  	if err != nil {
   309  		return nil, false, err
   310  	}
   311  
   312  	routeController := routecontroller.New(routes,
   313  		controllerContext.ClientBuilder.ClientOrDie("route-controller"),
   314  		controllerContext.InformerFactory.Core().V1().Nodes(),
   315  		controllerContext.ComponentConfig.KubeCloudShared.ClusterName,
   316  		clusterCIDRs)
   317  	go routeController.Run(ctx, controllerContext.ComponentConfig.KubeCloudShared.RouteReconciliationPeriod.Duration, controllerContext.ControllerManagerMetrics)
   318  	return nil, true, nil
   319  }
   320  
   321  func newPersistentVolumeBinderControllerDescriptor() *ControllerDescriptor {
   322  	return &ControllerDescriptor{
   323  		name:     names.PersistentVolumeBinderController,
   324  		aliases:  []string{"persistentvolume-binder"},
   325  		initFunc: startPersistentVolumeBinderController,
   326  	}
   327  }
   328  
   329  func startPersistentVolumeBinderController(ctx context.Context, controllerContext ControllerContext, controllerName string) (controller.Interface, bool, error) {
   330  	logger := klog.FromContext(ctx)
   331  	plugins, err := ProbeControllerVolumePlugins(logger, controllerContext.ComponentConfig.PersistentVolumeBinderController.VolumeConfiguration)
   332  	if err != nil {
   333  		return nil, true, fmt.Errorf("failed to probe volume plugins when starting persistentvolume controller: %v", err)
   334  	}
   335  
   336  	params := persistentvolumecontroller.ControllerParameters{
   337  		KubeClient:                controllerContext.ClientBuilder.ClientOrDie("persistent-volume-binder"),
   338  		SyncPeriod:                controllerContext.ComponentConfig.PersistentVolumeBinderController.PVClaimBinderSyncPeriod.Duration,
   339  		VolumePlugins:             plugins,
   340  		VolumeInformer:            controllerContext.InformerFactory.Core().V1().PersistentVolumes(),
   341  		ClaimInformer:             controllerContext.InformerFactory.Core().V1().PersistentVolumeClaims(),
   342  		ClassInformer:             controllerContext.InformerFactory.Storage().V1().StorageClasses(),
   343  		PodInformer:               controllerContext.InformerFactory.Core().V1().Pods(),
   344  		NodeInformer:              controllerContext.InformerFactory.Core().V1().Nodes(),
   345  		EnableDynamicProvisioning: controllerContext.ComponentConfig.PersistentVolumeBinderController.VolumeConfiguration.EnableDynamicProvisioning,
   346  	}
   347  	volumeController, volumeControllerErr := persistentvolumecontroller.NewController(ctx, params)
   348  	if volumeControllerErr != nil {
   349  		return nil, true, fmt.Errorf("failed to construct persistentvolume controller: %v", volumeControllerErr)
   350  	}
   351  	go volumeController.Run(ctx)
   352  	return nil, true, nil
   353  }
   354  
   355  func newPersistentVolumeAttachDetachControllerDescriptor() *ControllerDescriptor {
   356  	return &ControllerDescriptor{
   357  		name:     names.PersistentVolumeAttachDetachController,
   358  		aliases:  []string{"attachdetach"},
   359  		initFunc: startPersistentVolumeAttachDetachController,
   360  	}
   361  }
   362  
   363  func startPersistentVolumeAttachDetachController(ctx context.Context, controllerContext ControllerContext, controllerName string) (controller.Interface, bool, error) {
   364  	logger := klog.FromContext(ctx)
   365  	csiNodeInformer := controllerContext.InformerFactory.Storage().V1().CSINodes()
   366  	csiDriverInformer := controllerContext.InformerFactory.Storage().V1().CSIDrivers()
   367  
   368  	plugins, err := ProbeAttachableVolumePlugins(logger)
   369  	if err != nil {
   370  		return nil, true, fmt.Errorf("failed to probe volume plugins when starting attach/detach controller: %v", err)
   371  	}
   372  
   373  	ctx = klog.NewContext(ctx, logger)
   374  	attachDetachController, attachDetachControllerErr :=
   375  		attachdetach.NewAttachDetachController(
   376  			ctx,
   377  			controllerContext.ClientBuilder.ClientOrDie("attachdetach-controller"),
   378  			controllerContext.InformerFactory.Core().V1().Pods(),
   379  			controllerContext.InformerFactory.Core().V1().Nodes(),
   380  			controllerContext.InformerFactory.Core().V1().PersistentVolumeClaims(),
   381  			controllerContext.InformerFactory.Core().V1().PersistentVolumes(),
   382  			csiNodeInformer,
   383  			csiDriverInformer,
   384  			controllerContext.InformerFactory.Storage().V1().VolumeAttachments(),
   385  			plugins,
   386  			GetDynamicPluginProber(controllerContext.ComponentConfig.PersistentVolumeBinderController.VolumeConfiguration),
   387  			controllerContext.ComponentConfig.AttachDetachController.DisableAttachDetachReconcilerSync,
   388  			controllerContext.ComponentConfig.AttachDetachController.ReconcilerSyncLoopPeriod.Duration,
   389  			controllerContext.ComponentConfig.AttachDetachController.DisableForceDetachOnTimeout,
   390  			attachdetach.DefaultTimerConfig,
   391  		)
   392  	if attachDetachControllerErr != nil {
   393  		return nil, true, fmt.Errorf("failed to start attach/detach controller: %v", attachDetachControllerErr)
   394  	}
   395  	go attachDetachController.Run(ctx)
   396  	return nil, true, nil
   397  }
   398  
   399  func newPersistentVolumeExpanderControllerDescriptor() *ControllerDescriptor {
   400  	return &ControllerDescriptor{
   401  		name:     names.PersistentVolumeExpanderController,
   402  		aliases:  []string{"persistentvolume-expander"},
   403  		initFunc: startPersistentVolumeExpanderController,
   404  	}
   405  }
   406  
   407  func startPersistentVolumeExpanderController(ctx context.Context, controllerContext ControllerContext, controllerName string) (controller.Interface, bool, error) {
   408  	logger := klog.FromContext(ctx)
   409  	plugins, err := ProbeExpandableVolumePlugins(logger, controllerContext.ComponentConfig.PersistentVolumeBinderController.VolumeConfiguration)
   410  	if err != nil {
   411  		return nil, true, fmt.Errorf("failed to probe volume plugins when starting volume expand controller: %v", err)
   412  	}
   413  	csiTranslator := csitrans.New()
   414  
   415  	expandController, expandControllerErr := expand.NewExpandController(
   416  		ctx,
   417  		controllerContext.ClientBuilder.ClientOrDie("expand-controller"),
   418  		controllerContext.InformerFactory.Core().V1().PersistentVolumeClaims(),
   419  		plugins,
   420  		csiTranslator,
   421  		csimigration.NewPluginManager(csiTranslator, utilfeature.DefaultFeatureGate),
   422  	)
   423  
   424  	if expandControllerErr != nil {
   425  		return nil, true, fmt.Errorf("failed to start volume expand controller: %v", expandControllerErr)
   426  	}
   427  	go expandController.Run(ctx)
   428  	return nil, true, nil
   429  }
   430  
   431  func newEphemeralVolumeControllerDescriptor() *ControllerDescriptor {
   432  	return &ControllerDescriptor{
   433  		name:     names.EphemeralVolumeController,
   434  		aliases:  []string{"ephemeral-volume"},
   435  		initFunc: startEphemeralVolumeController,
   436  	}
   437  }
   438  
   439  func startEphemeralVolumeController(ctx context.Context, controllerContext ControllerContext, controllerName string) (controller.Interface, bool, error) {
   440  	ephemeralController, err := ephemeral.NewController(
   441  		ctx,
   442  		controllerContext.ClientBuilder.ClientOrDie("ephemeral-volume-controller"),
   443  		controllerContext.InformerFactory.Core().V1().Pods(),
   444  		controllerContext.InformerFactory.Core().V1().PersistentVolumeClaims())
   445  	if err != nil {
   446  		return nil, true, fmt.Errorf("failed to start ephemeral volume controller: %v", err)
   447  	}
   448  	go ephemeralController.Run(ctx, int(controllerContext.ComponentConfig.EphemeralVolumeController.ConcurrentEphemeralVolumeSyncs))
   449  	return nil, true, nil
   450  }
   451  
   452  const defaultResourceClaimControllerWorkers = 10
   453  
   454  func newResourceClaimControllerDescriptor() *ControllerDescriptor {
   455  	return &ControllerDescriptor{
   456  		name:     names.ResourceClaimController,
   457  		aliases:  []string{"resource-claim-controller"},
   458  		initFunc: startResourceClaimController,
   459  		requiredFeatureGates: []featuregate.Feature{
   460  			features.DynamicResourceAllocation, // TODO update app.TestFeatureGatedControllersShouldNotDefineAliases when removing this feature
   461  		},
   462  	}
   463  }
   464  
   465  func startResourceClaimController(ctx context.Context, controllerContext ControllerContext, controllerName string) (controller.Interface, bool, error) {
   466  	ephemeralController, err := resourceclaim.NewController(
   467  		klog.FromContext(ctx),
   468  		controllerContext.ClientBuilder.ClientOrDie("resource-claim-controller"),
   469  		controllerContext.InformerFactory.Core().V1().Pods(),
   470  		controllerContext.InformerFactory.Resource().V1alpha2().PodSchedulingContexts(),
   471  		controllerContext.InformerFactory.Resource().V1alpha2().ResourceClaims(),
   472  		controllerContext.InformerFactory.Resource().V1alpha2().ResourceClaimTemplates())
   473  	if err != nil {
   474  		return nil, true, fmt.Errorf("failed to start resource claim controller: %v", err)
   475  	}
   476  	go ephemeralController.Run(ctx, defaultResourceClaimControllerWorkers)
   477  	return nil, true, nil
   478  }
   479  
   480  func newEndpointsControllerDescriptor() *ControllerDescriptor {
   481  	return &ControllerDescriptor{
   482  		name:     names.EndpointsController,
   483  		aliases:  []string{"endpoint"},
   484  		initFunc: startEndpointsController,
   485  	}
   486  }
   487  
   488  func startEndpointsController(ctx context.Context, controllerContext ControllerContext, controllerName string) (controller.Interface, bool, error) {
   489  	go endpointcontroller.NewEndpointController(
   490  		ctx,
   491  		controllerContext.InformerFactory.Core().V1().Pods(),
   492  		controllerContext.InformerFactory.Core().V1().Services(),
   493  		controllerContext.InformerFactory.Core().V1().Endpoints(),
   494  		controllerContext.ClientBuilder.ClientOrDie("endpoint-controller"),
   495  		controllerContext.ComponentConfig.EndpointController.EndpointUpdatesBatchPeriod.Duration,
   496  	).Run(ctx, int(controllerContext.ComponentConfig.EndpointController.ConcurrentEndpointSyncs))
   497  	return nil, true, nil
   498  }
   499  
   500  func newReplicationControllerDescriptor() *ControllerDescriptor {
   501  	return &ControllerDescriptor{
   502  		name:     names.ReplicationControllerController,
   503  		aliases:  []string{"replicationcontroller"},
   504  		initFunc: startReplicationController,
   505  	}
   506  }
   507  
   508  func startReplicationController(ctx context.Context, controllerContext ControllerContext, controllerName string) (controller.Interface, bool, error) {
   509  	go replicationcontroller.NewReplicationManager(
   510  		ctx,
   511  		controllerContext.InformerFactory.Core().V1().Pods(),
   512  		controllerContext.InformerFactory.Core().V1().ReplicationControllers(),
   513  		controllerContext.ClientBuilder.ClientOrDie("replication-controller"),
   514  		replicationcontroller.BurstReplicas,
   515  	).Run(ctx, int(controllerContext.ComponentConfig.ReplicationController.ConcurrentRCSyncs))
   516  	return nil, true, nil
   517  }
   518  
   519  func newPodGarbageCollectorControllerDescriptor() *ControllerDescriptor {
   520  	return &ControllerDescriptor{
   521  		name:     names.PodGarbageCollectorController,
   522  		aliases:  []string{"podgc"},
   523  		initFunc: startPodGarbageCollectorController,
   524  	}
   525  }
   526  
   527  func startPodGarbageCollectorController(ctx context.Context, controllerContext ControllerContext, controllerName string) (controller.Interface, bool, error) {
   528  	go podgc.NewPodGC(
   529  		ctx,
   530  		controllerContext.ClientBuilder.ClientOrDie("pod-garbage-collector"),
   531  		controllerContext.InformerFactory.Core().V1().Pods(),
   532  		controllerContext.InformerFactory.Core().V1().Nodes(),
   533  		int(controllerContext.ComponentConfig.PodGCController.TerminatedPodGCThreshold),
   534  	).Run(ctx)
   535  	return nil, true, nil
   536  }
   537  
   538  func newResourceQuotaControllerDescriptor() *ControllerDescriptor {
   539  	return &ControllerDescriptor{
   540  		name:     names.ResourceQuotaController,
   541  		aliases:  []string{"resourcequota"},
   542  		initFunc: startResourceQuotaController,
   543  	}
   544  }
   545  
   546  func startResourceQuotaController(ctx context.Context, controllerContext ControllerContext, controllerName string) (controller.Interface, bool, error) {
   547  	resourceQuotaControllerClient := controllerContext.ClientBuilder.ClientOrDie("resourcequota-controller")
   548  	resourceQuotaControllerDiscoveryClient := controllerContext.ClientBuilder.DiscoveryClientOrDie("resourcequota-controller")
   549  	discoveryFunc := resourceQuotaControllerDiscoveryClient.ServerPreferredNamespacedResources
   550  	listerFuncForResource := generic.ListerFuncForResourceFunc(controllerContext.InformerFactory.ForResource)
   551  	quotaConfiguration := quotainstall.NewQuotaConfigurationForControllers(listerFuncForResource)
   552  
   553  	resourceQuotaControllerOptions := &resourcequotacontroller.ControllerOptions{
   554  		QuotaClient:               resourceQuotaControllerClient.CoreV1(),
   555  		ResourceQuotaInformer:     controllerContext.InformerFactory.Core().V1().ResourceQuotas(),
   556  		ResyncPeriod:              pkgcontroller.StaticResyncPeriodFunc(controllerContext.ComponentConfig.ResourceQuotaController.ResourceQuotaSyncPeriod.Duration),
   557  		InformerFactory:           controllerContext.ObjectOrMetadataInformerFactory,
   558  		ReplenishmentResyncPeriod: controllerContext.ResyncPeriod,
   559  		DiscoveryFunc:             discoveryFunc,
   560  		IgnoredResourcesFunc:      quotaConfiguration.IgnoredResources,
   561  		InformersStarted:          controllerContext.InformersStarted,
   562  		Registry:                  generic.NewRegistry(quotaConfiguration.Evaluators()),
   563  		UpdateFilter:              quotainstall.DefaultUpdateFilter(),
   564  	}
   565  	resourceQuotaController, err := resourcequotacontroller.NewController(ctx, resourceQuotaControllerOptions)
   566  	if err != nil {
   567  		return nil, false, err
   568  	}
   569  	go resourceQuotaController.Run(ctx, int(controllerContext.ComponentConfig.ResourceQuotaController.ConcurrentResourceQuotaSyncs))
   570  
   571  	// Periodically the quota controller to detect new resource types
   572  	go resourceQuotaController.Sync(ctx, discoveryFunc, 30*time.Second)
   573  
   574  	return nil, true, nil
   575  }
   576  
   577  func newNamespaceControllerDescriptor() *ControllerDescriptor {
   578  	return &ControllerDescriptor{
   579  		name:     names.NamespaceController,
   580  		aliases:  []string{"namespace"},
   581  		initFunc: startNamespaceController,
   582  	}
   583  }
   584  
   585  func startNamespaceController(ctx context.Context, controllerContext ControllerContext, controllerName string) (controller.Interface, bool, error) {
   586  	// the namespace cleanup controller is very chatty.  It makes lots of discovery calls and then it makes lots of delete calls
   587  	// the ratelimiter negatively affects its speed.  Deleting 100 total items in a namespace (that's only a few of each resource
   588  	// including events), takes ~10 seconds by default.
   589  	nsKubeconfig := controllerContext.ClientBuilder.ConfigOrDie("namespace-controller")
   590  	nsKubeconfig.QPS *= 20
   591  	nsKubeconfig.Burst *= 100
   592  	namespaceKubeClient := clientset.NewForConfigOrDie(nsKubeconfig)
   593  	return startModifiedNamespaceController(ctx, controllerContext, namespaceKubeClient, nsKubeconfig)
   594  }
   595  
   596  func startModifiedNamespaceController(ctx context.Context, controllerContext ControllerContext, namespaceKubeClient clientset.Interface, nsKubeconfig *restclient.Config) (controller.Interface, bool, error) {
   597  
   598  	metadataClient, err := metadata.NewForConfig(nsKubeconfig)
   599  	if err != nil {
   600  		return nil, true, err
   601  	}
   602  
   603  	discoverResourcesFn := namespaceKubeClient.Discovery().ServerPreferredNamespacedResources
   604  
   605  	namespaceController := namespacecontroller.NewNamespaceController(
   606  		ctx,
   607  		namespaceKubeClient,
   608  		metadataClient,
   609  		discoverResourcesFn,
   610  		controllerContext.InformerFactory.Core().V1().Namespaces(),
   611  		controllerContext.ComponentConfig.NamespaceController.NamespaceSyncPeriod.Duration,
   612  		v1.FinalizerKubernetes,
   613  	)
   614  	go namespaceController.Run(ctx, int(controllerContext.ComponentConfig.NamespaceController.ConcurrentNamespaceSyncs))
   615  
   616  	return nil, true, nil
   617  }
   618  
   619  func newServiceAccountControllerDescriptor() *ControllerDescriptor {
   620  	return &ControllerDescriptor{
   621  		name:     names.ServiceAccountController,
   622  		aliases:  []string{"serviceaccount"},
   623  		initFunc: startServiceAccountController,
   624  	}
   625  }
   626  
   627  func startServiceAccountController(ctx context.Context, controllerContext ControllerContext, controllerName string) (controller.Interface, bool, error) {
   628  	sac, err := serviceaccountcontroller.NewServiceAccountsController(
   629  		controllerContext.InformerFactory.Core().V1().ServiceAccounts(),
   630  		controllerContext.InformerFactory.Core().V1().Namespaces(),
   631  		controllerContext.ClientBuilder.ClientOrDie("service-account-controller"),
   632  		serviceaccountcontroller.DefaultServiceAccountsControllerOptions(),
   633  	)
   634  	if err != nil {
   635  		return nil, true, fmt.Errorf("error creating ServiceAccount controller: %v", err)
   636  	}
   637  	go sac.Run(ctx, 1)
   638  	return nil, true, nil
   639  }
   640  
   641  func newTTLControllerDescriptor() *ControllerDescriptor {
   642  	return &ControllerDescriptor{
   643  		name:     names.TTLController,
   644  		aliases:  []string{"ttl"},
   645  		initFunc: startTTLController,
   646  	}
   647  }
   648  
   649  func startTTLController(ctx context.Context, controllerContext ControllerContext, controllerName string) (controller.Interface, bool, error) {
   650  	go ttlcontroller.NewTTLController(
   651  		ctx,
   652  		controllerContext.InformerFactory.Core().V1().Nodes(),
   653  		controllerContext.ClientBuilder.ClientOrDie("ttl-controller"),
   654  	).Run(ctx, 5)
   655  	return nil, true, nil
   656  }
   657  
   658  func newGarbageCollectorControllerDescriptor() *ControllerDescriptor {
   659  	return &ControllerDescriptor{
   660  		name:     names.GarbageCollectorController,
   661  		aliases:  []string{"garbagecollector"},
   662  		initFunc: startGarbageCollectorController,
   663  	}
   664  }
   665  
   666  func startGarbageCollectorController(ctx context.Context, controllerContext ControllerContext, controllerName string) (controller.Interface, bool, error) {
   667  	if !controllerContext.ComponentConfig.GarbageCollectorController.EnableGarbageCollector {
   668  		return nil, false, nil
   669  	}
   670  
   671  	gcClientset := controllerContext.ClientBuilder.ClientOrDie("generic-garbage-collector")
   672  	discoveryClient := controllerContext.ClientBuilder.DiscoveryClientOrDie("generic-garbage-collector")
   673  
   674  	config := controllerContext.ClientBuilder.ConfigOrDie("generic-garbage-collector")
   675  	// Increase garbage collector controller's throughput: each object deletion takes two API calls,
   676  	// so to get |config.QPS| deletion rate we need to allow 2x more requests for this controller.
   677  	config.QPS *= 2
   678  	metadataClient, err := metadata.NewForConfig(config)
   679  	if err != nil {
   680  		return nil, true, err
   681  	}
   682  
   683  	ignoredResources := make(map[schema.GroupResource]struct{})
   684  	for _, r := range controllerContext.ComponentConfig.GarbageCollectorController.GCIgnoredResources {
   685  		ignoredResources[schema.GroupResource{Group: r.Group, Resource: r.Resource}] = struct{}{}
   686  	}
   687  
   688  	garbageCollector, err := garbagecollector.NewComposedGarbageCollector(
   689  		ctx,
   690  		gcClientset,
   691  		metadataClient,
   692  		controllerContext.RESTMapper,
   693  		controllerContext.GraphBuilder,
   694  	)
   695  	if err != nil {
   696  		return nil, true, fmt.Errorf("failed to start the generic garbage collector: %w", err)
   697  	}
   698  
   699  	// Start the garbage collector.
   700  	workers := int(controllerContext.ComponentConfig.GarbageCollectorController.ConcurrentGCSyncs)
   701  	go garbageCollector.Run(ctx, workers)
   702  
   703  	// Periodically refresh the RESTMapper with new discovery information and sync
   704  	// the garbage collector.
   705  	go garbageCollector.Sync(ctx, discoveryClient, 30*time.Second)
   706  
   707  	return garbageCollector, true, nil
   708  }
   709  
   710  func newPersistentVolumeClaimProtectionControllerDescriptor() *ControllerDescriptor {
   711  	return &ControllerDescriptor{
   712  		name:     names.PersistentVolumeClaimProtectionController,
   713  		aliases:  []string{"pvc-protection"},
   714  		initFunc: startPersistentVolumeClaimProtectionController,
   715  	}
   716  }
   717  
   718  func startPersistentVolumeClaimProtectionController(ctx context.Context, controllerContext ControllerContext, controllerName string) (controller.Interface, bool, error) {
   719  	pvcProtectionController, err := pvcprotection.NewPVCProtectionController(
   720  		klog.FromContext(ctx),
   721  		controllerContext.InformerFactory.Core().V1().PersistentVolumeClaims(),
   722  		controllerContext.InformerFactory.Core().V1().Pods(),
   723  		controllerContext.ClientBuilder.ClientOrDie("pvc-protection-controller"),
   724  	)
   725  	if err != nil {
   726  		return nil, true, fmt.Errorf("failed to start the pvc protection controller: %v", err)
   727  	}
   728  	go pvcProtectionController.Run(ctx, 1)
   729  	return nil, true, nil
   730  }
   731  
   732  func newPersistentVolumeProtectionControllerDescriptor() *ControllerDescriptor {
   733  	return &ControllerDescriptor{
   734  		name:     names.PersistentVolumeProtectionController,
   735  		aliases:  []string{"pv-protection"},
   736  		initFunc: startPersistentVolumeProtectionController,
   737  	}
   738  }
   739  
   740  func startPersistentVolumeProtectionController(ctx context.Context, controllerContext ControllerContext, controllerName string) (controller.Interface, bool, error) {
   741  	go pvprotection.NewPVProtectionController(
   742  		klog.FromContext(ctx),
   743  		controllerContext.InformerFactory.Core().V1().PersistentVolumes(),
   744  		controllerContext.ClientBuilder.ClientOrDie("pv-protection-controller"),
   745  	).Run(ctx, 1)
   746  	return nil, true, nil
   747  }
   748  
   749  func newTTLAfterFinishedControllerDescriptor() *ControllerDescriptor {
   750  	return &ControllerDescriptor{
   751  		name:     names.TTLAfterFinishedController,
   752  		aliases:  []string{"ttl-after-finished"},
   753  		initFunc: startTTLAfterFinishedController,
   754  	}
   755  }
   756  
   757  func startTTLAfterFinishedController(ctx context.Context, controllerContext ControllerContext, controllerName string) (controller.Interface, bool, error) {
   758  	go ttlafterfinished.New(
   759  		ctx,
   760  		controllerContext.InformerFactory.Batch().V1().Jobs(),
   761  		controllerContext.ClientBuilder.ClientOrDie("ttl-after-finished-controller"),
   762  	).Run(ctx, int(controllerContext.ComponentConfig.TTLAfterFinishedController.ConcurrentTTLSyncs))
   763  	return nil, true, nil
   764  }
   765  
   766  func newLegacyServiceAccountTokenCleanerControllerDescriptor() *ControllerDescriptor {
   767  	return &ControllerDescriptor{
   768  		name:     names.LegacyServiceAccountTokenCleanerController,
   769  		aliases:  []string{"legacy-service-account-token-cleaner"},
   770  		initFunc: startLegacyServiceAccountTokenCleanerController,
   771  	}
   772  }
   773  
   774  func startLegacyServiceAccountTokenCleanerController(ctx context.Context, controllerContext ControllerContext, controllerName string) (controller.Interface, bool, error) {
   775  	cleanUpPeriod := controllerContext.ComponentConfig.LegacySATokenCleaner.CleanUpPeriod.Duration
   776  	legacySATokenCleaner, err := serviceaccountcontroller.NewLegacySATokenCleaner(
   777  		controllerContext.InformerFactory.Core().V1().ServiceAccounts(),
   778  		controllerContext.InformerFactory.Core().V1().Secrets(),
   779  		controllerContext.InformerFactory.Core().V1().Pods(),
   780  		controllerContext.ClientBuilder.ClientOrDie("legacy-service-account-token-cleaner"),
   781  		clock.RealClock{},
   782  		serviceaccountcontroller.LegacySATokenCleanerOptions{
   783  			CleanUpPeriod: cleanUpPeriod,
   784  			SyncInterval:  serviceaccountcontroller.DefaultCleanerSyncInterval,
   785  		})
   786  	if err != nil {
   787  		return nil, true, fmt.Errorf("failed to start the legacy service account token cleaner: %v", err)
   788  	}
   789  	go legacySATokenCleaner.Run(ctx)
   790  	return nil, true, nil
   791  }
   792  
   793  // processCIDRs is a helper function that works on a comma separated cidrs and returns
   794  // a list of typed cidrs
   795  // error if failed to parse any of the cidrs or invalid length of cidrs
   796  func validateCIDRs(cidrsList string) ([]*net.IPNet, error) {
   797  	// failure: bad cidrs in config
   798  	clusterCIDRs, dualStack, err := processCIDRs(cidrsList)
   799  	if err != nil {
   800  		return nil, err
   801  	}
   802  
   803  	// failure: more than one cidr but they are not configured as dual stack
   804  	if len(clusterCIDRs) > 1 && !dualStack {
   805  		return nil, fmt.Errorf("len of ClusterCIDRs==%v and they are not configured as dual stack (at least one from each IPFamily", len(clusterCIDRs))
   806  	}
   807  
   808  	// failure: more than cidrs is not allowed even with dual stack
   809  	if len(clusterCIDRs) > 2 {
   810  		return nil, fmt.Errorf("length of clusterCIDRs is:%v more than max allowed of 2", len(clusterCIDRs))
   811  	}
   812  
   813  	return clusterCIDRs, nil
   814  }
   815  
   816  // processCIDRs is a helper function that works on a comma separated cidrs and returns
   817  // a list of typed cidrs
   818  // a flag if cidrs represents a dual stack
   819  // error if failed to parse any of the cidrs
   820  func processCIDRs(cidrsList string) ([]*net.IPNet, bool, error) {
   821  	cidrsSplit := strings.Split(strings.TrimSpace(cidrsList), ",")
   822  
   823  	cidrs, err := netutils.ParseCIDRs(cidrsSplit)
   824  	if err != nil {
   825  		return nil, false, err
   826  	}
   827  
   828  	// if cidrs has an error then the previous call will fail
   829  	// safe to ignore error checking on next call
   830  	dualstack, _ := netutils.IsDualStackCIDRs(cidrs)
   831  
   832  	return cidrs, dualstack, nil
   833  }
   834  
   835  // setNodeCIDRMaskSizes returns the IPv4 and IPv6 node cidr mask sizes to the value provided
   836  // for --node-cidr-mask-size-ipv4 and --node-cidr-mask-size-ipv6 respectively. If value not provided,
   837  // then it will return default IPv4 and IPv6 cidr mask sizes.
   838  func setNodeCIDRMaskSizes(cfg nodeipamconfig.NodeIPAMControllerConfiguration, clusterCIDRs []*net.IPNet) ([]int, error) {
   839  
   840  	sortedSizes := func(maskSizeIPv4, maskSizeIPv6 int) []int {
   841  		nodeMaskCIDRs := make([]int, len(clusterCIDRs))
   842  
   843  		for idx, clusterCIDR := range clusterCIDRs {
   844  			if netutils.IsIPv6CIDR(clusterCIDR) {
   845  				nodeMaskCIDRs[idx] = maskSizeIPv6
   846  			} else {
   847  				nodeMaskCIDRs[idx] = maskSizeIPv4
   848  			}
   849  		}
   850  		return nodeMaskCIDRs
   851  	}
   852  
   853  	// --node-cidr-mask-size flag is incompatible with dual stack clusters.
   854  	ipv4Mask, ipv6Mask := defaultNodeMaskCIDRIPv4, defaultNodeMaskCIDRIPv6
   855  	isDualstack := len(clusterCIDRs) > 1
   856  
   857  	// case one: cluster is dualstack (i.e, more than one cidr)
   858  	if isDualstack {
   859  		// if --node-cidr-mask-size then fail, user must configure the correct dual-stack mask sizes (or use default)
   860  		if cfg.NodeCIDRMaskSize != 0 {
   861  			return nil, errors.New("usage of --node-cidr-mask-size is not allowed with dual-stack clusters")
   862  
   863  		}
   864  
   865  		if cfg.NodeCIDRMaskSizeIPv4 != 0 {
   866  			ipv4Mask = int(cfg.NodeCIDRMaskSizeIPv4)
   867  		}
   868  		if cfg.NodeCIDRMaskSizeIPv6 != 0 {
   869  			ipv6Mask = int(cfg.NodeCIDRMaskSizeIPv6)
   870  		}
   871  		return sortedSizes(ipv4Mask, ipv6Mask), nil
   872  	}
   873  
   874  	maskConfigured := cfg.NodeCIDRMaskSize != 0
   875  	maskV4Configured := cfg.NodeCIDRMaskSizeIPv4 != 0
   876  	maskV6Configured := cfg.NodeCIDRMaskSizeIPv6 != 0
   877  	isSingleStackIPv6 := netutils.IsIPv6CIDR(clusterCIDRs[0])
   878  
   879  	// original flag is set
   880  	if maskConfigured {
   881  		// original mask flag is still the main reference.
   882  		if maskV4Configured || maskV6Configured {
   883  			return nil, errors.New("usage of --node-cidr-mask-size-ipv4 and --node-cidr-mask-size-ipv6 is not allowed if --node-cidr-mask-size is set. For dual-stack clusters please unset it and use IPFamily specific flags")
   884  		}
   885  
   886  		mask := int(cfg.NodeCIDRMaskSize)
   887  		return sortedSizes(mask, mask), nil
   888  	}
   889  
   890  	if maskV4Configured {
   891  		if isSingleStackIPv6 {
   892  			return nil, errors.New("usage of --node-cidr-mask-size-ipv4 is not allowed for a single-stack IPv6 cluster")
   893  		}
   894  
   895  		ipv4Mask = int(cfg.NodeCIDRMaskSizeIPv4)
   896  	}
   897  
   898  	// !maskV4Configured && !maskConfigured && maskV6Configured
   899  	if maskV6Configured {
   900  		if !isSingleStackIPv6 {
   901  			return nil, errors.New("usage of --node-cidr-mask-size-ipv6 is not allowed for a single-stack IPv4 cluster")
   902  		}
   903  
   904  		ipv6Mask = int(cfg.NodeCIDRMaskSizeIPv6)
   905  	}
   906  	return sortedSizes(ipv4Mask, ipv6Mask), nil
   907  }
   908  
   909  func newStorageVersionGarbageCollectorControllerDescriptor() *ControllerDescriptor {
   910  	return &ControllerDescriptor{
   911  		name:     names.StorageVersionGarbageCollectorController,
   912  		aliases:  []string{"storage-version-gc"},
   913  		initFunc: startStorageVersionGarbageCollectorController,
   914  		requiredFeatureGates: []featuregate.Feature{
   915  			genericfeatures.APIServerIdentity,
   916  			genericfeatures.StorageVersionAPI,
   917  		},
   918  	}
   919  }
   920  
   921  func startStorageVersionGarbageCollectorController(ctx context.Context, controllerContext ControllerContext, controllerName string) (controller.Interface, bool, error) {
   922  	go storageversiongc.NewStorageVersionGC(
   923  		ctx,
   924  		controllerContext.ClientBuilder.ClientOrDie("storage-version-garbage-collector"),
   925  		controllerContext.InformerFactory.Coordination().V1().Leases(),
   926  		controllerContext.InformerFactory.Internal().V1alpha1().StorageVersions(),
   927  	).Run(ctx)
   928  	return nil, true, nil
   929  }