k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/pkg/proxy/config/config.go (about)

     1  /*
     2  Copyright 2014 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 config
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"sync"
    23  	"time"
    24  
    25  	v1 "k8s.io/api/core/v1"
    26  	discoveryv1 "k8s.io/api/discovery/v1"
    27  	networkingv1alpha1 "k8s.io/api/networking/v1alpha1"
    28  	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
    29  	"k8s.io/apimachinery/pkg/util/sets"
    30  	v1informers "k8s.io/client-go/informers/core/v1"
    31  	discoveryv1informers "k8s.io/client-go/informers/discovery/v1"
    32  	networkingv1alpha1informers "k8s.io/client-go/informers/networking/v1alpha1"
    33  	"k8s.io/client-go/tools/cache"
    34  	"k8s.io/klog/v2"
    35  )
    36  
    37  // ServiceHandler is an abstract interface of objects which receive
    38  // notifications about service object changes.
    39  type ServiceHandler interface {
    40  	// OnServiceAdd is called whenever creation of new service object
    41  	// is observed.
    42  	OnServiceAdd(service *v1.Service)
    43  	// OnServiceUpdate is called whenever modification of an existing
    44  	// service object is observed.
    45  	OnServiceUpdate(oldService, service *v1.Service)
    46  	// OnServiceDelete is called whenever deletion of an existing service
    47  	// object is observed.
    48  	OnServiceDelete(service *v1.Service)
    49  	// OnServiceSynced is called once all the initial event handlers were
    50  	// called and the state is fully propagated to local cache.
    51  	OnServiceSynced()
    52  }
    53  
    54  // EndpointSliceHandler is an abstract interface of objects which receive
    55  // notifications about endpoint slice object changes.
    56  type EndpointSliceHandler interface {
    57  	// OnEndpointSliceAdd is called whenever creation of new endpoint slice
    58  	// object is observed.
    59  	OnEndpointSliceAdd(endpointSlice *discoveryv1.EndpointSlice)
    60  	// OnEndpointSliceUpdate is called whenever modification of an existing
    61  	// endpoint slice object is observed.
    62  	OnEndpointSliceUpdate(oldEndpointSlice, newEndpointSlice *discoveryv1.EndpointSlice)
    63  	// OnEndpointSliceDelete is called whenever deletion of an existing
    64  	// endpoint slice object is observed.
    65  	OnEndpointSliceDelete(endpointSlice *discoveryv1.EndpointSlice)
    66  	// OnEndpointSlicesSynced is called once all the initial event handlers were
    67  	// called and the state is fully propagated to local cache.
    68  	OnEndpointSlicesSynced()
    69  }
    70  
    71  // EndpointSliceConfig tracks a set of endpoints configurations.
    72  type EndpointSliceConfig struct {
    73  	listerSynced  cache.InformerSynced
    74  	eventHandlers []EndpointSliceHandler
    75  	logger        klog.Logger
    76  }
    77  
    78  // NewEndpointSliceConfig creates a new EndpointSliceConfig.
    79  func NewEndpointSliceConfig(ctx context.Context, endpointSliceInformer discoveryv1informers.EndpointSliceInformer, resyncPeriod time.Duration) *EndpointSliceConfig {
    80  	result := &EndpointSliceConfig{
    81  		listerSynced: endpointSliceInformer.Informer().HasSynced,
    82  		logger:       klog.FromContext(ctx),
    83  	}
    84  
    85  	_, _ = endpointSliceInformer.Informer().AddEventHandlerWithResyncPeriod(
    86  		cache.ResourceEventHandlerFuncs{
    87  			AddFunc:    result.handleAddEndpointSlice,
    88  			UpdateFunc: result.handleUpdateEndpointSlice,
    89  			DeleteFunc: result.handleDeleteEndpointSlice,
    90  		},
    91  		resyncPeriod,
    92  	)
    93  
    94  	return result
    95  }
    96  
    97  // RegisterEventHandler registers a handler which is called on every endpoint slice change.
    98  func (c *EndpointSliceConfig) RegisterEventHandler(handler EndpointSliceHandler) {
    99  	c.eventHandlers = append(c.eventHandlers, handler)
   100  }
   101  
   102  // Run waits for cache synced and invokes handlers after syncing.
   103  func (c *EndpointSliceConfig) Run(stopCh <-chan struct{}) {
   104  	c.logger.Info("Starting endpoint slice config controller")
   105  
   106  	if !cache.WaitForNamedCacheSync("endpoint slice config", stopCh, c.listerSynced) {
   107  		return
   108  	}
   109  
   110  	for _, h := range c.eventHandlers {
   111  		c.logger.V(3).Info("Calling handler.OnEndpointSlicesSynced()")
   112  		h.OnEndpointSlicesSynced()
   113  	}
   114  }
   115  
   116  func (c *EndpointSliceConfig) handleAddEndpointSlice(obj interface{}) {
   117  	endpointSlice, ok := obj.(*discoveryv1.EndpointSlice)
   118  	if !ok {
   119  		utilruntime.HandleError(fmt.Errorf("unexpected object type: %T", obj))
   120  		return
   121  	}
   122  	for _, h := range c.eventHandlers {
   123  		c.logger.V(4).Info("Calling handler.OnEndpointSliceAdd", "endpoints", klog.KObj(endpointSlice))
   124  		h.OnEndpointSliceAdd(endpointSlice)
   125  	}
   126  }
   127  
   128  func (c *EndpointSliceConfig) handleUpdateEndpointSlice(oldObj, newObj interface{}) {
   129  	oldEndpointSlice, ok := oldObj.(*discoveryv1.EndpointSlice)
   130  	if !ok {
   131  		utilruntime.HandleError(fmt.Errorf("unexpected object type: %T", newObj))
   132  		return
   133  	}
   134  	newEndpointSlice, ok := newObj.(*discoveryv1.EndpointSlice)
   135  	if !ok {
   136  		utilruntime.HandleError(fmt.Errorf("unexpected object type: %T", newObj))
   137  		return
   138  	}
   139  	for _, h := range c.eventHandlers {
   140  		c.logger.V(4).Info("Calling handler.OnEndpointSliceUpdate")
   141  		h.OnEndpointSliceUpdate(oldEndpointSlice, newEndpointSlice)
   142  	}
   143  }
   144  
   145  func (c *EndpointSliceConfig) handleDeleteEndpointSlice(obj interface{}) {
   146  	endpointSlice, ok := obj.(*discoveryv1.EndpointSlice)
   147  	if !ok {
   148  		tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
   149  		if !ok {
   150  			utilruntime.HandleError(fmt.Errorf("unexpected object type: %T", obj))
   151  			return
   152  		}
   153  		if endpointSlice, ok = tombstone.Obj.(*discoveryv1.EndpointSlice); !ok {
   154  			utilruntime.HandleError(fmt.Errorf("unexpected object type: %T", obj))
   155  			return
   156  		}
   157  	}
   158  	for _, h := range c.eventHandlers {
   159  		c.logger.V(4).Info("Calling handler.OnEndpointsDelete")
   160  		h.OnEndpointSliceDelete(endpointSlice)
   161  	}
   162  }
   163  
   164  // ServiceConfig tracks a set of service configurations.
   165  type ServiceConfig struct {
   166  	listerSynced  cache.InformerSynced
   167  	eventHandlers []ServiceHandler
   168  	logger        klog.Logger
   169  }
   170  
   171  // NewServiceConfig creates a new ServiceConfig.
   172  func NewServiceConfig(ctx context.Context, serviceInformer v1informers.ServiceInformer, resyncPeriod time.Duration) *ServiceConfig {
   173  	result := &ServiceConfig{
   174  		listerSynced: serviceInformer.Informer().HasSynced,
   175  		logger:       klog.FromContext(ctx),
   176  	}
   177  
   178  	_, _ = serviceInformer.Informer().AddEventHandlerWithResyncPeriod(
   179  		cache.ResourceEventHandlerFuncs{
   180  			AddFunc:    result.handleAddService,
   181  			UpdateFunc: result.handleUpdateService,
   182  			DeleteFunc: result.handleDeleteService,
   183  		},
   184  		resyncPeriod,
   185  	)
   186  
   187  	return result
   188  }
   189  
   190  // RegisterEventHandler registers a handler which is called on every service change.
   191  func (c *ServiceConfig) RegisterEventHandler(handler ServiceHandler) {
   192  	c.eventHandlers = append(c.eventHandlers, handler)
   193  }
   194  
   195  // Run waits for cache synced and invokes handlers after syncing.
   196  func (c *ServiceConfig) Run(stopCh <-chan struct{}) {
   197  	c.logger.Info("Starting service config controller")
   198  
   199  	if !cache.WaitForNamedCacheSync("service config", stopCh, c.listerSynced) {
   200  		return
   201  	}
   202  
   203  	for i := range c.eventHandlers {
   204  		c.logger.V(3).Info("Calling handler.OnServiceSynced()")
   205  		c.eventHandlers[i].OnServiceSynced()
   206  	}
   207  }
   208  
   209  func (c *ServiceConfig) handleAddService(obj interface{}) {
   210  	service, ok := obj.(*v1.Service)
   211  	if !ok {
   212  		utilruntime.HandleError(fmt.Errorf("unexpected object type: %v", obj))
   213  		return
   214  	}
   215  	for i := range c.eventHandlers {
   216  		c.logger.V(4).Info("Calling handler.OnServiceAdd")
   217  		c.eventHandlers[i].OnServiceAdd(service)
   218  	}
   219  }
   220  
   221  func (c *ServiceConfig) handleUpdateService(oldObj, newObj interface{}) {
   222  	oldService, ok := oldObj.(*v1.Service)
   223  	if !ok {
   224  		utilruntime.HandleError(fmt.Errorf("unexpected object type: %v", oldObj))
   225  		return
   226  	}
   227  	service, ok := newObj.(*v1.Service)
   228  	if !ok {
   229  		utilruntime.HandleError(fmt.Errorf("unexpected object type: %v", newObj))
   230  		return
   231  	}
   232  	for i := range c.eventHandlers {
   233  		c.logger.V(4).Info("Calling handler.OnServiceUpdate")
   234  		c.eventHandlers[i].OnServiceUpdate(oldService, service)
   235  	}
   236  }
   237  
   238  func (c *ServiceConfig) handleDeleteService(obj interface{}) {
   239  	service, ok := obj.(*v1.Service)
   240  	if !ok {
   241  		tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
   242  		if !ok {
   243  			utilruntime.HandleError(fmt.Errorf("unexpected object type: %v", obj))
   244  			return
   245  		}
   246  		if service, ok = tombstone.Obj.(*v1.Service); !ok {
   247  			utilruntime.HandleError(fmt.Errorf("unexpected object type: %v", obj))
   248  			return
   249  		}
   250  	}
   251  	for i := range c.eventHandlers {
   252  		c.logger.V(4).Info("Calling handler.OnServiceDelete")
   253  		c.eventHandlers[i].OnServiceDelete(service)
   254  	}
   255  }
   256  
   257  // NodeHandler is an abstract interface of objects which receive
   258  // notifications about node object changes.
   259  type NodeHandler interface {
   260  	// OnNodeAdd is called whenever creation of new node object
   261  	// is observed.
   262  	OnNodeAdd(node *v1.Node)
   263  	// OnNodeUpdate is called whenever modification of an existing
   264  	// node object is observed.
   265  	OnNodeUpdate(oldNode, node *v1.Node)
   266  	// OnNodeDelete is called whenever deletion of an existing node
   267  	// object is observed.
   268  	OnNodeDelete(node *v1.Node)
   269  	// OnNodeSynced is called once all the initial event handlers were
   270  	// called and the state is fully propagated to local cache.
   271  	OnNodeSynced()
   272  }
   273  
   274  // NoopNodeHandler is a noop handler for proxiers that have not yet
   275  // implemented a full NodeHandler.
   276  type NoopNodeHandler struct{}
   277  
   278  // OnNodeAdd is a noop handler for Node creates.
   279  func (*NoopNodeHandler) OnNodeAdd(node *v1.Node) {}
   280  
   281  // OnNodeUpdate is a noop handler for Node updates.
   282  func (*NoopNodeHandler) OnNodeUpdate(oldNode, node *v1.Node) {}
   283  
   284  // OnNodeDelete is a noop handler for Node deletes.
   285  func (*NoopNodeHandler) OnNodeDelete(node *v1.Node) {}
   286  
   287  // OnNodeSynced is a noop handler for Node syncs.
   288  func (*NoopNodeHandler) OnNodeSynced() {}
   289  
   290  var _ NodeHandler = &NoopNodeHandler{}
   291  
   292  // NodeConfig tracks a set of node configurations.
   293  // It accepts "set", "add" and "remove" operations of node via channels, and invokes registered handlers on change.
   294  type NodeConfig struct {
   295  	listerSynced  cache.InformerSynced
   296  	eventHandlers []NodeHandler
   297  	logger        klog.Logger
   298  }
   299  
   300  // NewNodeConfig creates a new NodeConfig.
   301  func NewNodeConfig(ctx context.Context, nodeInformer v1informers.NodeInformer, resyncPeriod time.Duration) *NodeConfig {
   302  	result := &NodeConfig{
   303  		listerSynced: nodeInformer.Informer().HasSynced,
   304  		logger:       klog.FromContext(ctx),
   305  	}
   306  
   307  	_, _ = nodeInformer.Informer().AddEventHandlerWithResyncPeriod(
   308  		cache.ResourceEventHandlerFuncs{
   309  			AddFunc:    result.handleAddNode,
   310  			UpdateFunc: result.handleUpdateNode,
   311  			DeleteFunc: result.handleDeleteNode,
   312  		},
   313  		resyncPeriod,
   314  	)
   315  
   316  	return result
   317  }
   318  
   319  // RegisterEventHandler registers a handler which is called on every node change.
   320  func (c *NodeConfig) RegisterEventHandler(handler NodeHandler) {
   321  	c.eventHandlers = append(c.eventHandlers, handler)
   322  }
   323  
   324  // Run starts the goroutine responsible for calling registered handlers.
   325  func (c *NodeConfig) Run(stopCh <-chan struct{}) {
   326  	c.logger.Info("Starting node config controller")
   327  
   328  	if !cache.WaitForNamedCacheSync("node config", stopCh, c.listerSynced) {
   329  		return
   330  	}
   331  
   332  	for i := range c.eventHandlers {
   333  		c.logger.V(3).Info("Calling handler.OnNodeSynced()")
   334  		c.eventHandlers[i].OnNodeSynced()
   335  	}
   336  }
   337  
   338  func (c *NodeConfig) handleAddNode(obj interface{}) {
   339  	node, ok := obj.(*v1.Node)
   340  	if !ok {
   341  		utilruntime.HandleError(fmt.Errorf("unexpected object type: %v", obj))
   342  		return
   343  	}
   344  	for i := range c.eventHandlers {
   345  		c.logger.V(4).Info("Calling handler.OnNodeAdd")
   346  		c.eventHandlers[i].OnNodeAdd(node)
   347  	}
   348  }
   349  
   350  func (c *NodeConfig) handleUpdateNode(oldObj, newObj interface{}) {
   351  	oldNode, ok := oldObj.(*v1.Node)
   352  	if !ok {
   353  		utilruntime.HandleError(fmt.Errorf("unexpected object type: %v", oldObj))
   354  		return
   355  	}
   356  	node, ok := newObj.(*v1.Node)
   357  	if !ok {
   358  		utilruntime.HandleError(fmt.Errorf("unexpected object type: %v", newObj))
   359  		return
   360  	}
   361  	for i := range c.eventHandlers {
   362  		c.logger.V(5).Info("Calling handler.OnNodeUpdate")
   363  		c.eventHandlers[i].OnNodeUpdate(oldNode, node)
   364  	}
   365  }
   366  
   367  func (c *NodeConfig) handleDeleteNode(obj interface{}) {
   368  	node, ok := obj.(*v1.Node)
   369  	if !ok {
   370  		tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
   371  		if !ok {
   372  			utilruntime.HandleError(fmt.Errorf("unexpected object type: %v", obj))
   373  			return
   374  		}
   375  		if node, ok = tombstone.Obj.(*v1.Node); !ok {
   376  			utilruntime.HandleError(fmt.Errorf("unexpected object type: %v", obj))
   377  			return
   378  		}
   379  	}
   380  	for i := range c.eventHandlers {
   381  		c.logger.V(4).Info("Calling handler.OnNodeDelete")
   382  		c.eventHandlers[i].OnNodeDelete(node)
   383  	}
   384  }
   385  
   386  // ServiceCIDRHandler is an abstract interface of objects which receive
   387  // notifications about ServiceCIDR object changes.
   388  type ServiceCIDRHandler interface {
   389  	// OnServiceCIDRsChanged is called whenever a change is observed
   390  	// in any of the ServiceCIDRs, and provides complete list of service cidrs.
   391  	OnServiceCIDRsChanged(cidrs []string)
   392  }
   393  
   394  // ServiceCIDRConfig tracks a set of service configurations.
   395  type ServiceCIDRConfig struct {
   396  	listerSynced  cache.InformerSynced
   397  	eventHandlers []ServiceCIDRHandler
   398  	mu            sync.Mutex
   399  	cidrs         sets.Set[string]
   400  	logger        klog.Logger
   401  }
   402  
   403  // NewServiceCIDRConfig creates a new ServiceCIDRConfig.
   404  func NewServiceCIDRConfig(ctx context.Context, serviceCIDRInformer networkingv1alpha1informers.ServiceCIDRInformer, resyncPeriod time.Duration) *ServiceCIDRConfig {
   405  	result := &ServiceCIDRConfig{
   406  		listerSynced: serviceCIDRInformer.Informer().HasSynced,
   407  		cidrs:        sets.New[string](),
   408  		logger:       klog.FromContext(ctx),
   409  	}
   410  
   411  	_, _ = serviceCIDRInformer.Informer().AddEventHandlerWithResyncPeriod(
   412  		cache.ResourceEventHandlerFuncs{
   413  			AddFunc: func(obj interface{}) {
   414  				result.handleServiceCIDREvent(nil, obj)
   415  			},
   416  			UpdateFunc: func(oldObj, newObj interface{}) {
   417  				result.handleServiceCIDREvent(oldObj, newObj)
   418  			},
   419  			DeleteFunc: func(obj interface{}) {
   420  				result.handleServiceCIDREvent(obj, nil)
   421  			},
   422  		},
   423  		resyncPeriod,
   424  	)
   425  	return result
   426  }
   427  
   428  // RegisterEventHandler registers a handler which is called on every ServiceCIDR change.
   429  func (c *ServiceCIDRConfig) RegisterEventHandler(handler ServiceCIDRHandler) {
   430  	c.eventHandlers = append(c.eventHandlers, handler)
   431  }
   432  
   433  // Run waits for cache synced and invokes handlers after syncing.
   434  func (c *ServiceCIDRConfig) Run(stopCh <-chan struct{}) {
   435  	c.logger.Info("Starting serviceCIDR config controller")
   436  
   437  	if !cache.WaitForNamedCacheSync("serviceCIDR config", stopCh, c.listerSynced) {
   438  		return
   439  	}
   440  	c.handleServiceCIDREvent(nil, nil)
   441  }
   442  
   443  // handleServiceCIDREvent is a helper function to handle Add, Update and Delete
   444  // events on ServiceCIDR objects and call downstream event handlers.
   445  func (c *ServiceCIDRConfig) handleServiceCIDREvent(oldObj, newObj interface{}) {
   446  	var oldServiceCIDR, newServiceCIDR *networkingv1alpha1.ServiceCIDR
   447  	var ok bool
   448  
   449  	if oldObj != nil {
   450  		oldServiceCIDR, ok = oldObj.(*networkingv1alpha1.ServiceCIDR)
   451  		if !ok {
   452  			utilruntime.HandleError(fmt.Errorf("unexpected object type: %v", oldObj))
   453  			return
   454  		}
   455  	}
   456  
   457  	if newObj != nil {
   458  		newServiceCIDR, ok = newObj.(*networkingv1alpha1.ServiceCIDR)
   459  		if !ok {
   460  			utilruntime.HandleError(fmt.Errorf("unexpected object type: %v", newObj))
   461  			return
   462  		}
   463  	}
   464  
   465  	c.mu.Lock()
   466  	defer c.mu.Unlock()
   467  
   468  	if oldServiceCIDR != nil {
   469  		c.cidrs.Delete(oldServiceCIDR.Spec.CIDRs...)
   470  	}
   471  
   472  	if newServiceCIDR != nil {
   473  		c.cidrs.Insert(newServiceCIDR.Spec.CIDRs...)
   474  	}
   475  
   476  	for i := range c.eventHandlers {
   477  		c.logger.V(4).Info("Calling handler.OnServiceCIDRsChanged")
   478  		c.eventHandlers[i].OnServiceCIDRsChanged(c.cidrs.UnsortedList())
   479  	}
   480  }