k8s.io/kubernetes@v1.29.3/pkg/controller/nodeipam/ipam/controller_legacyprovider.go (about)

     1  //go:build !providerless
     2  // +build !providerless
     3  
     4  /*
     5  Copyright 2017 The Kubernetes Authors.
     6  
     7  Licensed under the Apache License, Version 2.0 (the "License");
     8  you may not use this file except in compliance with the License.
     9  You may obtain a copy of the License at
    10  
    11      http://www.apache.org/licenses/LICENSE-2.0
    12  
    13  Unless required by applicable law or agreed to in writing, software
    14  distributed under the License is distributed on an "AS IS" BASIS,
    15  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    16  See the License for the specific language governing permissions and
    17  limitations under the License.
    18  */
    19  
    20  package ipam
    21  
    22  import (
    23  	"context"
    24  	"fmt"
    25  	"net"
    26  	"sync"
    27  	"time"
    28  
    29  	"k8s.io/klog/v2"
    30  	netutils "k8s.io/utils/net"
    31  
    32  	v1 "k8s.io/api/core/v1"
    33  	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
    34  	informers "k8s.io/client-go/informers/core/v1"
    35  	clientset "k8s.io/client-go/kubernetes"
    36  	"k8s.io/client-go/tools/cache"
    37  	cloudprovider "k8s.io/cloud-provider"
    38  	"k8s.io/kubernetes/pkg/controller/nodeipam/ipam/cidrset"
    39  	nodesync "k8s.io/kubernetes/pkg/controller/nodeipam/ipam/sync"
    40  	controllerutil "k8s.io/kubernetes/pkg/controller/util/node"
    41  	"k8s.io/legacy-cloud-providers/gce"
    42  )
    43  
    44  // Config for the IPAM controller.
    45  type Config struct {
    46  	// Resync is the default timeout duration when there are no errors.
    47  	Resync time.Duration
    48  	// MaxBackoff is the maximum timeout when in a error backoff state.
    49  	MaxBackoff time.Duration
    50  	// InitialRetry is the initial retry interval when an error is reported.
    51  	InitialRetry time.Duration
    52  	// Mode to use to synchronize.
    53  	Mode nodesync.NodeSyncMode
    54  }
    55  
    56  // Controller is the controller for synchronizing cluster and cloud node
    57  // pod CIDR range assignments.
    58  type Controller struct {
    59  	config  *Config
    60  	adapter *adapter
    61  
    62  	lock    sync.Mutex
    63  	syncers map[string]*nodesync.NodeSync
    64  
    65  	set *cidrset.CidrSet
    66  }
    67  
    68  // NewController returns a new instance of the IPAM controller.
    69  func NewController(
    70  	config *Config,
    71  	kubeClient clientset.Interface,
    72  	cloud cloudprovider.Interface,
    73  	clusterCIDR, serviceCIDR *net.IPNet,
    74  	nodeCIDRMaskSize int) (*Controller, error) {
    75  
    76  	if !nodesync.IsValidMode(config.Mode) {
    77  		return nil, fmt.Errorf("invalid IPAM controller mode %q", config.Mode)
    78  	}
    79  
    80  	gceCloud, ok := cloud.(*gce.Cloud)
    81  	if !ok {
    82  		return nil, fmt.Errorf("cloud IPAM controller does not support %q provider", cloud.ProviderName())
    83  	}
    84  
    85  	set, err := cidrset.NewCIDRSet(clusterCIDR, nodeCIDRMaskSize)
    86  	if err != nil {
    87  		return nil, err
    88  	}
    89  
    90  	c := &Controller{
    91  		config:  config,
    92  		adapter: newAdapter(kubeClient, gceCloud),
    93  		syncers: make(map[string]*nodesync.NodeSync),
    94  		set:     set,
    95  	}
    96  
    97  	if err := occupyServiceCIDR(c.set, clusterCIDR, serviceCIDR); err != nil {
    98  		return nil, err
    99  	}
   100  
   101  	//check whether there is a remaining cidr after occupyServiceCIDR
   102  	cidr, err := c.set.AllocateNext()
   103  	switch err {
   104  	case cidrset.ErrCIDRRangeNoCIDRsRemaining:
   105  		return nil, fmt.Errorf("failed after occupy serviceCIDR: %v", err)
   106  	case nil:
   107  		err := c.set.Release(cidr)
   108  		return c, err
   109  	default:
   110  		return nil, fmt.Errorf("unexpected error when check remaining CIDR range: %v", err)
   111  	}
   112  }
   113  
   114  // Start initializes the Controller with the existing list of nodes and
   115  // registers the informers for node changes. This will start synchronization
   116  // of the node and cloud CIDR range allocations.
   117  func (c *Controller) Start(logger klog.Logger, nodeInformer informers.NodeInformer) error {
   118  	logger.Info("Starting IPAM controller", "config", c.config)
   119  
   120  	nodes, err := listNodes(logger, c.adapter.k8s)
   121  	if err != nil {
   122  		return err
   123  	}
   124  	for _, node := range nodes.Items {
   125  		if node.Spec.PodCIDR != "" {
   126  			_, cidrRange, err := netutils.ParseCIDRSloppy(node.Spec.PodCIDR)
   127  			if err == nil {
   128  				c.set.Occupy(cidrRange)
   129  				logger.V(3).Info("Occupying CIDR for node", "CIDR", node.Spec.PodCIDR, "node", klog.KObj(&node))
   130  			} else {
   131  				logger.Error(err, "Node has an invalid CIDR", "node", klog.KObj(&node), "CIDR", node.Spec.PodCIDR)
   132  			}
   133  		}
   134  
   135  		func() {
   136  			c.lock.Lock()
   137  			defer c.lock.Unlock()
   138  
   139  			// XXX/bowei -- stagger the start of each sync cycle.
   140  			syncer := c.newSyncer(node.Name)
   141  			c.syncers[node.Name] = syncer
   142  			go syncer.Loop(logger, nil)
   143  		}()
   144  	}
   145  
   146  	nodeInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
   147  		AddFunc: controllerutil.CreateAddNodeHandler(func(node *v1.Node) error {
   148  			return c.onAdd(logger, node)
   149  		}),
   150  		UpdateFunc: controllerutil.CreateUpdateNodeHandler(func(_, newNode *v1.Node) error {
   151  			return c.onUpdate(logger, newNode)
   152  		}),
   153  		DeleteFunc: controllerutil.CreateDeleteNodeHandler(logger, func(node *v1.Node) error {
   154  			return c.onDelete(logger, node)
   155  		}),
   156  	})
   157  
   158  	return nil
   159  }
   160  
   161  func (c *Controller) Run(ctx context.Context) {
   162  	defer utilruntime.HandleCrash()
   163  
   164  	go c.adapter.Run(ctx)
   165  	<-ctx.Done()
   166  }
   167  
   168  // occupyServiceCIDR removes the service CIDR range from the cluster CIDR if it
   169  // intersects.
   170  func occupyServiceCIDR(set *cidrset.CidrSet, clusterCIDR, serviceCIDR *net.IPNet) error {
   171  	if clusterCIDR.Contains(serviceCIDR.IP) || serviceCIDR.Contains(clusterCIDR.IP) {
   172  		if err := set.Occupy(serviceCIDR); err != nil {
   173  			return err
   174  		}
   175  	}
   176  	return nil
   177  }
   178  
   179  type nodeState struct {
   180  	t Timeout
   181  }
   182  
   183  func (ns *nodeState) ReportResult(err error) {
   184  	ns.t.Update(err == nil)
   185  }
   186  
   187  func (ns *nodeState) ResyncTimeout() time.Duration {
   188  	return ns.t.Next()
   189  }
   190  
   191  func (c *Controller) newSyncer(name string) *nodesync.NodeSync {
   192  	ns := &nodeState{
   193  		Timeout{
   194  			Resync:       c.config.Resync,
   195  			MaxBackoff:   c.config.MaxBackoff,
   196  			InitialRetry: c.config.InitialRetry,
   197  		},
   198  	}
   199  	return nodesync.New(ns, c.adapter, c.adapter, c.config.Mode, name, c.set)
   200  }
   201  
   202  func (c *Controller) onAdd(logger klog.Logger, node *v1.Node) error {
   203  	c.lock.Lock()
   204  	defer c.lock.Unlock()
   205  
   206  	syncer, ok := c.syncers[node.Name]
   207  	if !ok {
   208  		syncer = c.newSyncer(node.Name)
   209  		c.syncers[node.Name] = syncer
   210  		go syncer.Loop(logger, nil)
   211  	} else {
   212  		logger.Info("Add for node that already exists", "node", klog.KObj(node))
   213  	}
   214  	syncer.Update(node)
   215  
   216  	return nil
   217  }
   218  
   219  func (c *Controller) onUpdate(logger klog.Logger, node *v1.Node) error {
   220  	c.lock.Lock()
   221  	defer c.lock.Unlock()
   222  
   223  	if sync, ok := c.syncers[node.Name]; ok {
   224  		sync.Update(node)
   225  	} else {
   226  		logger.Error(nil, "Received update for non-existent node", "node", klog.KObj(node))
   227  		return fmt.Errorf("unknown node %q", node.Name)
   228  	}
   229  
   230  	return nil
   231  }
   232  
   233  func (c *Controller) onDelete(logger klog.Logger, node *v1.Node) error {
   234  	c.lock.Lock()
   235  	defer c.lock.Unlock()
   236  
   237  	if syncer, ok := c.syncers[node.Name]; ok {
   238  		syncer.Delete(node)
   239  		delete(c.syncers, node.Name)
   240  	} else {
   241  		logger.Info("Node was already deleted", "node", klog.KObj(node))
   242  	}
   243  
   244  	return nil
   245  }