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 }