github.com/cilium/cilium@v1.16.2/operator/pkg/ciliumenvoyconfig/ciliumenvoyconfig_reconcile.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 package ciliumenvoyconfig 5 6 import ( 7 "context" 8 "fmt" 9 "strconv" 10 11 "github.com/sirupsen/logrus" 12 corev1 "k8s.io/api/core/v1" 13 k8serrors "k8s.io/apimachinery/pkg/api/errors" 14 "k8s.io/apimachinery/pkg/types" 15 ctrl "sigs.k8s.io/controller-runtime" 16 "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" 17 18 ciliumv2 "github.com/cilium/cilium/pkg/k8s/apis/cilium.io/v2" 19 "github.com/cilium/cilium/pkg/logging/logfields" 20 ) 21 22 const ( 23 ciliumEnvoyLBPrefix = "cilium-envoy-lb" 24 ) 25 26 func (r *ciliumEnvoyConfigReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { 27 scopedLog := r.logger.WithFields(logrus.Fields{ 28 logfields.Controller: "ciliumenvoyconfig", 29 logfields.Resource: req.NamespacedName, 30 }) 31 scopedLog.Info("Starting reconciliation") 32 33 svc := &corev1.Service{} 34 if err := r.client.Get(ctx, req.NamespacedName, svc); err != nil { 35 if k8serrors.IsNotFound(err) { 36 scopedLog.WithError(err).Debug("Unable to get service - either deleted or not yet available") 37 return ctrl.Result{}, nil 38 } 39 40 return ctrl.Result{}, err 41 } 42 43 if isLBProtocolAnnotationEnabled(svc) || hasAnyPort(svc, r.ports) { 44 if err := r.createOrUpdateEnvoyConfig(ctx, svc); err != nil { 45 return ctrl.Result{}, err 46 } 47 } else { 48 if err := r.deleteEnvoyConfig(ctx, svc); err != nil { 49 return ctrl.Result{}, err 50 } 51 } 52 53 scopedLog.Info("Successfully reconciled") 54 return ctrl.Result{}, nil 55 } 56 57 func hasAnyPort(svc *corev1.Service, ports []string) bool { 58 for _, p := range ports { 59 for _, port := range svc.Spec.Ports { 60 if p == getServiceFrontendPort(port) { 61 return true 62 } 63 } 64 } 65 return false 66 } 67 68 func getServiceFrontendPort(port corev1.ServicePort) string { 69 if port.Port != 0 { 70 return strconv.Itoa(int(port.Port)) 71 } 72 if port.NodePort != 0 { 73 return strconv.Itoa(int(port.NodePort)) 74 } 75 return port.Name 76 } 77 78 func (r *ciliumEnvoyConfigReconciler) createOrUpdateEnvoyConfig(ctx context.Context, svc *corev1.Service) error { 79 desired, err := r.getEnvoyConfigForService(svc) 80 if err != nil { 81 return fmt.Errorf("failed to get CiliumEnvoyConfig for service: %w", err) 82 } 83 84 if err := controllerutil.SetControllerReference(svc, desired, r.client.Scheme()); err != nil { 85 return fmt.Errorf("failed to set owner reference: %w", err) 86 } 87 88 exists := true 89 existing := ciliumv2.CiliumEnvoyConfig{} 90 if err := r.client.Get(ctx, types.NamespacedName{Namespace: desired.Namespace, Name: desired.Name}, &existing); err != nil { 91 if !k8serrors.IsNotFound(err) { 92 return fmt.Errorf(" failed to lookup CiliumEnvoyConfig: %w", err) 93 } 94 exists = false 95 } 96 97 scopedLog := r.logger.WithField(logfields.ServiceKey, getName(svc)) 98 if exists { 99 if desired.DeepEqual(&existing) { 100 r.logger.WithField(logfields.CiliumEnvoyConfigName, fmt.Sprintf("%s/%s", desired.Namespace, desired.Name)).Debug("No change for existing CiliumEnvoyConfig") 101 return nil 102 } 103 104 // Update existing CEC 105 updated := existing.DeepCopy() 106 updated.Spec = desired.Spec 107 108 scopedLog.Debug("Updating CiliumEnvoyConfig") 109 if err := r.client.Update(ctx, updated); err != nil { 110 return fmt.Errorf("failed to update CiliumEnvoyConfig for service: %w", err) 111 } 112 113 scopedLog.Debug("Updated CiliumEnvoyConfig for service") 114 return nil 115 } 116 117 scopedLog.Debug("Creating CiliumEnvoyConfig") 118 if err := r.client.Create(ctx, desired); err != nil { 119 return fmt.Errorf("failed to create CiliumEnvoyConfig for service: %w", err) 120 } 121 122 scopedLog.Debug("Created CiliumEnvoyConfig for service") 123 return nil 124 } 125 126 func (r *ciliumEnvoyConfigReconciler) deleteEnvoyConfig(ctx context.Context, svc *corev1.Service) error { 127 existing := ciliumv2.CiliumEnvoyConfig{} 128 if err := r.client.Get(ctx, types.NamespacedName{Namespace: svc.Namespace, Name: fmt.Sprintf("%s-%s", ciliumEnvoyLBPrefix, svc.Name)}, &existing); err != nil { 129 if !k8serrors.IsNotFound(err) { 130 return fmt.Errorf("failed to lookup CiliumEnvoyConfig: %w", err) 131 } 132 return nil 133 } 134 135 r.logger.Debug("Deleting CiliumEnvoyConfig") 136 if err := r.client.Delete(ctx, &existing); err != nil { 137 return fmt.Errorf("failed to delete CiliumEnvoyConfig for service: %w", err) 138 } 139 140 return nil 141 }