k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/pkg/controller/nodeipam/ipam/cidr_allocator.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 ipam
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"net"
    23  	"time"
    24  
    25  	"k8s.io/kubernetes/pkg/controller/nodeipam/ipam/cidrset"
    26  
    27  	v1 "k8s.io/api/core/v1"
    28  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    29  	"k8s.io/apimachinery/pkg/fields"
    30  	"k8s.io/apimachinery/pkg/labels"
    31  	"k8s.io/apimachinery/pkg/util/wait"
    32  	informers "k8s.io/client-go/informers/core/v1"
    33  	clientset "k8s.io/client-go/kubernetes"
    34  	cloudprovider "k8s.io/cloud-provider"
    35  	"k8s.io/klog/v2"
    36  )
    37  
    38  // CIDRAllocatorType is the type of the allocator to use.
    39  type CIDRAllocatorType string
    40  
    41  const (
    42  	// RangeAllocatorType is the allocator that uses an internal CIDR
    43  	// range allocator to do node CIDR range allocations.
    44  	RangeAllocatorType CIDRAllocatorType = "RangeAllocator"
    45  	// CloudAllocatorType is the allocator that uses cloud platform
    46  	// support to do node CIDR range allocations.
    47  	CloudAllocatorType CIDRAllocatorType = "CloudAllocator"
    48  	// IPAMFromClusterAllocatorType uses the ipam controller sync'ing the node
    49  	// CIDR range allocations from the cluster to the cloud.
    50  	IPAMFromClusterAllocatorType = "IPAMFromCluster"
    51  	// IPAMFromCloudAllocatorType uses the ipam controller sync'ing the node
    52  	// CIDR range allocations from the cloud to the cluster.
    53  	IPAMFromCloudAllocatorType = "IPAMFromCloud"
    54  )
    55  
    56  // TODO: figure out the good setting for those constants.
    57  const (
    58  	// The amount of time the nodecontroller polls on the list nodes endpoint.
    59  	apiserverStartupGracePeriod = 10 * time.Minute
    60  
    61  	// The no. of NodeSpec updates NC can process concurrently.
    62  	cidrUpdateWorkers = 30
    63  
    64  	// cidrUpdateRetries is the no. of times a NodeSpec update will be retried before dropping it.
    65  	cidrUpdateRetries = 3
    66  )
    67  
    68  // nodePollInterval is used in listing node
    69  var nodePollInterval = 10 * time.Second
    70  
    71  // CIDRAllocator is an interface implemented by things that know how
    72  // to allocate/occupy/recycle CIDR for nodes.
    73  type CIDRAllocator interface {
    74  	// AllocateOrOccupyCIDR looks at the given node, assigns it a valid
    75  	// CIDR if it doesn't currently have one or mark the CIDR as used if
    76  	// the node already have one.
    77  	AllocateOrOccupyCIDR(ctx context.Context, node *v1.Node) error
    78  	// ReleaseCIDR releases the CIDR of the removed node.
    79  	ReleaseCIDR(logger klog.Logger, node *v1.Node) error
    80  	// Run starts all the working logic of the allocator.
    81  	Run(ctx context.Context)
    82  }
    83  
    84  // CIDRAllocatorParams is parameters that's required for creating new
    85  // cidr range allocator.
    86  type CIDRAllocatorParams struct {
    87  	// ClusterCIDRs is list of cluster cidrs.
    88  	ClusterCIDRs []*net.IPNet
    89  	// ServiceCIDR is primary service cidr for cluster.
    90  	ServiceCIDR *net.IPNet
    91  	// SecondaryServiceCIDR is secondary service cidr for cluster.
    92  	SecondaryServiceCIDR *net.IPNet
    93  	// NodeCIDRMaskSizes is list of node cidr mask sizes.
    94  	NodeCIDRMaskSizes []int
    95  }
    96  
    97  // New creates a new CIDR range allocator.
    98  func New(ctx context.Context, kubeClient clientset.Interface, cloud cloudprovider.Interface, nodeInformer informers.NodeInformer, allocatorType CIDRAllocatorType, allocatorParams CIDRAllocatorParams) (CIDRAllocator, error) {
    99  	nodeList, err := listNodes(ctx, kubeClient)
   100  	if err != nil {
   101  		return nil, err
   102  	}
   103  
   104  	switch allocatorType {
   105  	case RangeAllocatorType:
   106  		return NewCIDRRangeAllocator(ctx, kubeClient, nodeInformer, allocatorParams, nodeList)
   107  	default:
   108  		return nil, fmt.Errorf("invalid CIDR allocator type: %v", allocatorType)
   109  	}
   110  }
   111  
   112  func listNodes(ctx context.Context, kubeClient clientset.Interface) (*v1.NodeList, error) {
   113  	var nodeList *v1.NodeList
   114  	logger := klog.FromContext(ctx)
   115  
   116  	// We must poll because apiserver might not be up. This error causes
   117  	// controller manager to restart.
   118  	if pollErr := wait.PollUntilContextTimeout(ctx, nodePollInterval, apiserverStartupGracePeriod, true, func(ctx context.Context) (bool, error) {
   119  		var err error
   120  		nodeList, err = kubeClient.CoreV1().Nodes().List(ctx, metav1.ListOptions{
   121  			FieldSelector: fields.Everything().String(),
   122  			LabelSelector: labels.Everything().String(),
   123  		})
   124  		if err != nil {
   125  			logger.Error(err, "Failed to list all nodes")
   126  			return false, nil
   127  		}
   128  		return true, nil
   129  	}); pollErr != nil {
   130  		return nil, fmt.Errorf("failed to list all nodes in %v, cannot proceed without updating CIDR map",
   131  			apiserverStartupGracePeriod)
   132  	}
   133  	return nodeList, nil
   134  }
   135  
   136  // ipnetToStringList converts a slice of net.IPNet into a list of CIDR in string format
   137  func ipnetToStringList(inCIDRs []*net.IPNet) []string {
   138  	outCIDRs := make([]string, len(inCIDRs))
   139  	for idx, inCIDR := range inCIDRs {
   140  		outCIDRs[idx] = inCIDR.String()
   141  	}
   142  	return outCIDRs
   143  }
   144  
   145  // occupyServiceCIDR removes the service CIDR range from the cluster CIDR if it
   146  // intersects.
   147  func occupyServiceCIDR(set *cidrset.CidrSet, clusterCIDR, serviceCIDR *net.IPNet) error {
   148  	if clusterCIDR.Contains(serviceCIDR.IP) || serviceCIDR.Contains(clusterCIDR.IP) {
   149  		if err := set.Occupy(serviceCIDR); err != nil {
   150  			return err
   151  		}
   152  	}
   153  	return nil
   154  }