k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/pkg/controlplane/controller/defaultservicecidr/default_servicecidr_controller.go (about)

     1  /*
     2  Copyright 2023 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 defaultservicecidr
    18  
    19  import (
    20  	"context"
    21  	"net"
    22  	"reflect"
    23  	"time"
    24  
    25  	v1 "k8s.io/api/core/v1"
    26  	networkingapiv1alpha1 "k8s.io/api/networking/v1alpha1"
    27  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    28  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    29  	"k8s.io/apimachinery/pkg/fields"
    30  	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
    31  	"k8s.io/apimachinery/pkg/util/wait"
    32  	metav1apply "k8s.io/client-go/applyconfigurations/meta/v1"
    33  	networkingapiv1alpha1apply "k8s.io/client-go/applyconfigurations/networking/v1alpha1"
    34  	networkingv1alpha1informers "k8s.io/client-go/informers/networking/v1alpha1"
    35  	clientset "k8s.io/client-go/kubernetes"
    36  	"k8s.io/client-go/kubernetes/scheme"
    37  	v1core "k8s.io/client-go/kubernetes/typed/core/v1"
    38  	networkingv1alpha1listers "k8s.io/client-go/listers/networking/v1alpha1"
    39  	"k8s.io/client-go/tools/cache"
    40  	"k8s.io/client-go/tools/record"
    41  	"k8s.io/klog/v2"
    42  )
    43  
    44  const (
    45  	controllerName         = "kubernetes-service-cidr-controller"
    46  	DefaultServiceCIDRName = "kubernetes"
    47  )
    48  
    49  // NewController returns a new *Controller that generates the default ServiceCIDR
    50  // from the `--service-cluster-ip-range` flag and recreates it if necessary,
    51  // but doesn't update it if is different.
    52  // It follows the same logic that the kubernetes.default Service.
    53  func NewController(
    54  	primaryRange net.IPNet,
    55  	secondaryRange net.IPNet,
    56  	client clientset.Interface,
    57  ) *Controller {
    58  	c := &Controller{
    59  		client:   client,
    60  		interval: 10 * time.Second, // same as DefaultEndpointReconcilerInterval
    61  	}
    62  
    63  	// obtain configuration from flags
    64  	c.cidrs = append(c.cidrs, primaryRange.String())
    65  	if secondaryRange.IP != nil {
    66  		c.cidrs = append(c.cidrs, secondaryRange.String())
    67  	}
    68  	// instead of using the shared informers from the controlplane instance, we construct our own informer
    69  	// because we need such a small subset of the information available, only the kubernetes.default ServiceCIDR
    70  	c.serviceCIDRInformer = networkingv1alpha1informers.NewFilteredServiceCIDRInformer(client, 12*time.Hour,
    71  		cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc},
    72  		func(options *metav1.ListOptions) {
    73  			options.FieldSelector = fields.OneTermEqualSelector("metadata.name", DefaultServiceCIDRName).String()
    74  		})
    75  
    76  	c.serviceCIDRLister = networkingv1alpha1listers.NewServiceCIDRLister(c.serviceCIDRInformer.GetIndexer())
    77  	c.serviceCIDRsSynced = c.serviceCIDRInformer.HasSynced
    78  
    79  	return c
    80  }
    81  
    82  // Controller manages selector-based service ipAddress.
    83  type Controller struct {
    84  	cidrs []string // order matters, first cidr defines the default IP family
    85  
    86  	client           clientset.Interface
    87  	eventBroadcaster record.EventBroadcaster
    88  	eventRecorder    record.EventRecorder
    89  
    90  	serviceCIDRInformer cache.SharedIndexInformer
    91  	serviceCIDRLister   networkingv1alpha1listers.ServiceCIDRLister
    92  	serviceCIDRsSynced  cache.InformerSynced
    93  
    94  	interval time.Duration
    95  }
    96  
    97  // Start will not return until the default ServiceCIDR exists or stopCh is closed.
    98  func (c *Controller) Start(ctx context.Context) {
    99  	defer utilruntime.HandleCrash()
   100  	stopCh := ctx.Done()
   101  
   102  	c.eventBroadcaster = record.NewBroadcaster(record.WithContext(ctx))
   103  	c.eventRecorder = c.eventBroadcaster.NewRecorder(scheme.Scheme, v1.EventSource{Component: controllerName})
   104  	c.eventBroadcaster.StartStructuredLogging(0)
   105  	c.eventBroadcaster.StartRecordingToSink(&v1core.EventSinkImpl{Interface: c.client.CoreV1().Events("")})
   106  	defer c.eventBroadcaster.Shutdown()
   107  
   108  	klog.Infof("Starting %s", controllerName)
   109  	defer klog.Infof("Shutting down %s", controllerName)
   110  
   111  	go c.serviceCIDRInformer.Run(stopCh)
   112  	if !cache.WaitForNamedCacheSync(controllerName, stopCh, c.serviceCIDRsSynced) {
   113  		return
   114  	}
   115  
   116  	// wait until first successfully sync
   117  	// this blocks apiserver startup so poll with a short interval
   118  	err := wait.PollUntilContextCancel(ctx, 100*time.Millisecond, true, func(ctx context.Context) (bool, error) {
   119  		syncErr := c.sync()
   120  		return syncErr == nil, nil
   121  	})
   122  	if err != nil {
   123  		klog.Infof("error initializing the default ServiceCIDR: %v", err)
   124  
   125  	}
   126  
   127  	// run the sync loop in the background with the defined interval
   128  	go wait.Until(func() {
   129  		err := c.sync()
   130  		if err != nil {
   131  			klog.Infof("error trying to sync the default ServiceCIDR: %v", err)
   132  		}
   133  	}, c.interval, stopCh)
   134  }
   135  
   136  func (c *Controller) sync() error {
   137  	// check if the default ServiceCIDR already exist
   138  	serviceCIDR, err := c.serviceCIDRLister.Get(DefaultServiceCIDRName)
   139  	// if exists
   140  	if err == nil {
   141  		c.syncStatus(serviceCIDR)
   142  		return nil
   143  	}
   144  
   145  	// unknown error
   146  	if !apierrors.IsNotFound(err) {
   147  		return err
   148  	}
   149  
   150  	// default ServiceCIDR does not exist
   151  	klog.Infof("Creating default ServiceCIDR with CIDRs: %v", c.cidrs)
   152  	serviceCIDR = &networkingapiv1alpha1.ServiceCIDR{
   153  		ObjectMeta: metav1.ObjectMeta{
   154  			Name: DefaultServiceCIDRName,
   155  		},
   156  		Spec: networkingapiv1alpha1.ServiceCIDRSpec{
   157  			CIDRs: c.cidrs,
   158  		},
   159  	}
   160  	serviceCIDR, err = c.client.NetworkingV1alpha1().ServiceCIDRs().Create(context.Background(), serviceCIDR, metav1.CreateOptions{})
   161  	if err != nil && !apierrors.IsAlreadyExists(err) {
   162  		c.eventRecorder.Eventf(serviceCIDR, v1.EventTypeWarning, "KubernetesDefaultServiceCIDRError", "The default ServiceCIDR can not be created")
   163  		return err
   164  	}
   165  	c.syncStatus(serviceCIDR)
   166  	return nil
   167  }
   168  
   169  func (c *Controller) syncStatus(serviceCIDR *networkingapiv1alpha1.ServiceCIDR) {
   170  	// don't sync the status of the ServiceCIDR if is being deleted,
   171  	// deletion must be handled by the controller-manager
   172  	if !serviceCIDR.GetDeletionTimestamp().IsZero() {
   173  		return
   174  	}
   175  
   176  	// This controller will set the Ready condition to true if the Ready condition
   177  	// does not exist and the CIDR values match this controller CIDR values.
   178  	for _, condition := range serviceCIDR.Status.Conditions {
   179  		if condition.Type == networkingapiv1alpha1.ServiceCIDRConditionReady {
   180  			if condition.Status == metav1.ConditionTrue {
   181  				return
   182  			}
   183  			klog.Infof("default ServiceCIDR condition Ready is not True: %v", condition.Status)
   184  			c.eventRecorder.Eventf(serviceCIDR, v1.EventTypeWarning, condition.Reason, condition.Message)
   185  			return
   186  		}
   187  	}
   188  	// set status to ready if the ServiceCIDR matches this configuration
   189  	if reflect.DeepEqual(c.cidrs, serviceCIDR.Spec.CIDRs) {
   190  		klog.Infof("Setting default ServiceCIDR condition Ready to True")
   191  		svcApplyStatus := networkingapiv1alpha1apply.ServiceCIDRStatus().WithConditions(
   192  			metav1apply.Condition().
   193  				WithType(networkingapiv1alpha1.ServiceCIDRConditionReady).
   194  				WithStatus(metav1.ConditionTrue).
   195  				WithMessage("Kubernetes default Service CIDR is ready").
   196  				WithLastTransitionTime(metav1.Now()))
   197  		svcApply := networkingapiv1alpha1apply.ServiceCIDR(DefaultServiceCIDRName).WithStatus(svcApplyStatus)
   198  		if _, errApply := c.client.NetworkingV1alpha1().ServiceCIDRs().ApplyStatus(context.Background(), svcApply, metav1.ApplyOptions{FieldManager: controllerName, Force: true}); errApply != nil {
   199  			klog.Infof("error updating default ServiceCIDR status: %v", errApply)
   200  			c.eventRecorder.Eventf(serviceCIDR, v1.EventTypeWarning, "KubernetesDefaultServiceCIDRError", "The default ServiceCIDR Status can not be set to Ready=True")
   201  		}
   202  	}
   203  }