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 }