From 175c2ff6242b4286b2b3bbacb4076d31f903cbbe Mon Sep 17 00:00:00 2001 From: facchettos Date: Fri, 19 Jul 2024 10:54:31 +0200 Subject: [PATCH 1/2] added patch logic for services --- pkg/controllers/resources/services/syncer.go | 64 ++++++++------- .../resources/services/syncer_test.go | 20 ++--- .../resources/services/translate.go | 79 ++++--------------- 3 files changed, 57 insertions(+), 106 deletions(-) diff --git a/pkg/controllers/resources/services/syncer.go b/pkg/controllers/resources/services/syncer.go index fc30fa29d..2bca231d6 100644 --- a/pkg/controllers/resources/services/syncer.go +++ b/pkg/controllers/resources/services/syncer.go @@ -3,6 +3,7 @@ package services import ( "context" "errors" + "fmt" "time" "github.com/loft-sh/vcluster/pkg/controllers/syncer" @@ -10,10 +11,11 @@ import ( "github.com/loft-sh/vcluster/pkg/controllers/syncer/translator" syncertypes "github.com/loft-sh/vcluster/pkg/controllers/syncer/types" "github.com/loft-sh/vcluster/pkg/mappings" + "github.com/loft-sh/vcluster/pkg/patcher" "github.com/loft-sh/vcluster/pkg/specialservices" corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/equality" kerrors "k8s.io/apimachinery/pkg/api/errors" + utilerrors "k8s.io/apimachinery/pkg/util/errors" "k8s.io/klog/v2" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" @@ -54,7 +56,7 @@ func (s *serviceSyncer) SyncToHost(ctx *synccontext.SyncContext, vObj client.Obj return s.SyncToHostCreate(ctx, vObj, s.translate(ctx, vObj.(*corev1.Service))) } -func (s *serviceSyncer) Sync(ctx *synccontext.SyncContext, pObj client.Object, vObj client.Object) (ctrl.Result, error) { +func (s *serviceSyncer) Sync(ctx *synccontext.SyncContext, pObj client.Object, vObj client.Object) (_ ctrl.Result, retErr error) { vService := vObj.(*corev1.Service) pService := pObj.(*corev1.Service) @@ -63,6 +65,25 @@ func (s *serviceSyncer) Sync(ctx *synccontext.SyncContext, pObj client.Object, v return ctrl.Result{RequeueAfter: time.Second * 3}, nil } + shouldPatch := false + patch, err := patcher.NewSyncerPatcher(ctx, pService, vService) + if err != nil { + return ctrl.Result{}, fmt.Errorf("new syncer patcher: %w", err) + } + + defer func() { + if !shouldPatch { + return + } + + if err := patch.Patch(ctx, pService, vService); err != nil { + retErr = utilerrors.NewAggregate([]error{retErr, err}) + } + if retErr != nil { + s.EventRecorder().Eventf(vObj, "Warning", "SyncError", "Error syncing: %v", retErr) + } + }() + // check if backwards update is necessary newService := s.translateUpdateBackwards(pService, vService) if newService != nil { @@ -71,45 +92,22 @@ func (s *serviceSyncer) Sync(ctx *synccontext.SyncContext, pObj client.Object, v ctx.Log.Infof("recreating virtual service %s/%s, because cluster ip differs %s != %s", vService.Namespace, vService.Name, pService.Spec.ClusterIP, vService.Spec.ClusterIP) // recreate the new service with the correct cluster ip - _, err := recreateService(ctx, ctx.VirtualClient, newService) + vService, err = recreateService(ctx, ctx.VirtualClient, newService) if err != nil { ctx.Log.Errorf("error creating virtual service: %s/%s", vService.Namespace, vService.Name) - return ctrl.Result{}, err } } else { - // update with correct ports - ctx.Log.Infof("update virtual service %s/%s, because spec is out of sync", vService.Namespace, vService.Name) - err := ctx.VirtualClient.Update(ctx, newService) - if err != nil { - return ctrl.Result{}, err - } + newService.DeepCopyInto(vService) + shouldPatch = true } - - // we will requeue anyways - return ctrl.Result{Requeue: true}, nil - } - - // check if backwards status update is necessary - if !equality.Semantic.DeepEqual(vService.Status, pService.Status) { - newService := vService.DeepCopy() - newService.Status = pService.Status - ctx.Log.Infof("update virtual service %s/%s, because status is out of sync", vService.Namespace, vService.Name) - translator.PrintChanges(vService, newService, ctx.Log) - err := ctx.VirtualClient.Status().Update(ctx, newService) - if err != nil { - return ctrl.Result{}, err - } - - return ctrl.Result{Requeue: true}, nil + return ctrl.Result{Requeue: true}, err } - + shouldPatch = true + vService.Status = pService.Status // forward update - newService = s.translateUpdate(ctx, pService, vService) - if newService != nil { - translator.PrintChanges(pService, newService, ctx.Log) - } + s.translateUpdate(ctx, pService, vService) - return s.SyncToHostUpdate(ctx, vObj, newService) + return ctrl.Result{}, nil } func isSwitchingFromExternalName(pService *corev1.Service, vService *corev1.Service) bool { diff --git a/pkg/controllers/resources/services/syncer_test.go b/pkg/controllers/resources/services/syncer_test.go index 26450e382..03e356ffb 100644 --- a/pkg/controllers/resources/services/syncer_test.go +++ b/pkg/controllers/resources/services/syncer_test.go @@ -332,7 +332,7 @@ func TestSync(t *testing.T) { }, Sync: func(ctx *synccontext.RegisterContext) { syncCtx, syncer := generictesting.FakeStartSyncer(t, ctx, New) - _, err := syncer.(*serviceSyncer).Sync(syncCtx, pServicePorts1, vServicePorts1) + _, err := syncer.(*serviceSyncer).Sync(syncCtx, pServicePorts1.DeepCopy(), vServicePorts1.DeepCopy()) assert.NilError(t, err) }, }, @@ -348,7 +348,7 @@ func TestSync(t *testing.T) { }, Sync: func(ctx *synccontext.RegisterContext) { syncCtx, syncer := generictesting.FakeStartSyncer(t, ctx, New) - _, err := syncer.(*serviceSyncer).Sync(syncCtx, pServicePorts2, vServicePorts1) + _, err := syncer.(*serviceSyncer).Sync(syncCtx, pServicePorts2.DeepCopy(), vServicePorts1.DeepCopy()) assert.NilError(t, err) }, }, @@ -364,7 +364,7 @@ func TestSync(t *testing.T) { }, Sync: func(ctx *synccontext.RegisterContext) { syncCtx, syncer := generictesting.FakeStartSyncer(t, ctx, New) - _, err := syncer.(*serviceSyncer).Sync(syncCtx, createdByServerService, updateForwardService) + _, err := syncer.(*serviceSyncer).Sync(syncCtx, createdByServerService.DeepCopy(), updateForwardService.DeepCopy()) assert.NilError(t, err) }, }, @@ -380,7 +380,7 @@ func TestSync(t *testing.T) { }, Sync: func(ctx *synccontext.RegisterContext) { syncCtx, syncer := generictesting.FakeStartSyncer(t, ctx, New) - _, err := syncer.(*serviceSyncer).Sync(syncCtx, createdService, baseService) + _, err := syncer.(*serviceSyncer).Sync(syncCtx, createdService.DeepCopy(), baseService.DeepCopy()) assert.NilError(t, err) }, }, @@ -408,7 +408,7 @@ func TestSync(t *testing.T) { assert.NilError(t, err) baseService.Spec.ExternalName = updateBackwardSpecService.Spec.ExternalName - _, err = syncer.(*serviceSyncer).Sync(syncCtx, updateBackwardSpecService, baseService) + _, err = syncer.(*serviceSyncer).Sync(syncCtx, updateBackwardSpecService.DeepCopy(), baseService.DeepCopy()) assert.NilError(t, err) }, }, @@ -436,7 +436,7 @@ func TestSync(t *testing.T) { assert.NilError(t, err) baseService.Spec.ExternalName = updateBackwardSpecService.Spec.ExternalName - _, err = syncer.(*serviceSyncer).Sync(syncCtx, updateBackwardSpecRecreateService, baseService) + _, err = syncer.(*serviceSyncer).Sync(syncCtx, updateBackwardSpecRecreateService.DeepCopy(), baseService.DeepCopy()) assert.NilError(t, err) }, }, @@ -452,7 +452,7 @@ func TestSync(t *testing.T) { }, Sync: func(ctx *synccontext.RegisterContext) { syncCtx, syncer := generictesting.FakeStartSyncer(t, ctx, New) - _, err := syncer.(*serviceSyncer).Sync(syncCtx, updateBackwardStatusService, baseService) + _, err := syncer.(*serviceSyncer).Sync(syncCtx, updateBackwardStatusService.DeepCopy(), baseService.DeepCopy()) assert.NilError(t, err) }, }, @@ -468,7 +468,7 @@ func TestSync(t *testing.T) { }, Sync: func(ctx *synccontext.RegisterContext) { syncCtx, syncer := generictesting.FakeStartSyncer(t, ctx, New) - _, err := syncer.(*serviceSyncer).Sync(syncCtx, createdService, baseService) + _, err := syncer.(*serviceSyncer).Sync(syncCtx, createdService.DeepCopy(), baseService.DeepCopy()) assert.NilError(t, err) }, }, @@ -556,7 +556,7 @@ func TestSync(t *testing.T) { }, Sync: func(ctx *synccontext.RegisterContext) { syncCtx, syncer := generictesting.FakeStartSyncer(t, ctx, New) - _, err := syncer.(*serviceSyncer).Sync(syncCtx, pServiceExternal, vServiceClusterIPFromExternal) + _, err := syncer.(*serviceSyncer).Sync(syncCtx, pServiceExternal.DeepCopy(), vServiceClusterIPFromExternal.DeepCopy()) assert.NilError(t, err) }, }, @@ -572,7 +572,7 @@ func TestSync(t *testing.T) { }, Sync: func(ctx *synccontext.RegisterContext) { syncCtx, syncer := generictesting.FakeStartSyncer(t, ctx, New) - _, err := syncer.(*serviceSyncer).Sync(syncCtx, pServiceExternal, vServiceNodePortFromExternal) + _, err := syncer.(*serviceSyncer).Sync(syncCtx, pServiceExternal.DeepCopy(), vServiceNodePortFromExternal.DeepCopy()) assert.NilError(t, err) }, }, diff --git a/pkg/controllers/resources/services/translate.go b/pkg/controllers/resources/services/translate.go index 2b5c04685..4f10c1a3e 100644 --- a/pkg/controllers/resources/services/translate.go +++ b/pkg/controllers/resources/services/translate.go @@ -2,6 +2,7 @@ package services import ( "context" + "slices" "github.com/loft-sh/vcluster/pkg/controllers/syncer/translator" "github.com/loft-sh/vcluster/pkg/util/translate" @@ -76,85 +77,37 @@ func (s *serviceSyncer) translateUpdateBackwards(pObj, vObj *corev1.Service) *co return updated } -func (s *serviceSyncer) translateUpdate(ctx context.Context, pObj, vObj *corev1.Service) *corev1.Service { - var updated *corev1.Service - +func (s *serviceSyncer) translateUpdate(ctx context.Context, pObj, vObj *corev1.Service) { // check annotations _, updatedAnnotations, updatedLabels := s.TranslateMetadataUpdate(ctx, vObj, pObj) // remove the ServiceBlockDeletion annotation if it's not needed if vObj.Spec.ClusterIP == pObj.Spec.ClusterIP { delete(updatedAnnotations, ServiceBlockDeletion) } - if !equality.Semantic.DeepEqual(updatedAnnotations, pObj.Annotations) || !equality.Semantic.DeepEqual(updatedLabels, pObj.Labels) { - updated = translator.NewIfNil(updated, pObj) - updated.Annotations = updatedAnnotations - updated.Labels = updatedLabels - } + pObj.Annotations = updatedAnnotations + pObj.Labels = updatedLabels - // check ports - if !equality.Semantic.DeepEqual(vObj.Spec.Ports, pObj.Spec.Ports) { - updated = translator.NewIfNil(updated, pObj) - updated.Spec.Ports = vObj.Spec.Ports + pObj.Spec.Ports = slices.Clone(vObj.Spec.Ports) - // make sure node ports will be reset here - StripNodePorts(updated) - } + // make sure node ports will be reset here + StripNodePorts(pObj) - // publish not ready addresses - if vObj.Spec.PublishNotReadyAddresses != pObj.Spec.PublishNotReadyAddresses { - updated = translator.NewIfNil(updated, pObj) - updated.Spec.PublishNotReadyAddresses = vObj.Spec.PublishNotReadyAddresses - } + pObj.Spec.PublishNotReadyAddresses = vObj.Spec.PublishNotReadyAddresses - // type - if vObj.Spec.Type != pObj.Spec.Type { - updated = translator.NewIfNil(updated, pObj) - updated.Spec.Type = vObj.Spec.Type - } + pObj.Spec.Type = vObj.Spec.Type - // external name - if vObj.Spec.ExternalName != pObj.Spec.ExternalName { - updated = translator.NewIfNil(updated, pObj) - updated.Spec.ExternalName = vObj.Spec.ExternalName - } + pObj.Spec.ExternalName = vObj.Spec.ExternalName - // externalTrafficPolicy - if vObj.Spec.ExternalTrafficPolicy != pObj.Spec.ExternalTrafficPolicy { - updated = translator.NewIfNil(updated, pObj) - updated.Spec.ExternalTrafficPolicy = vObj.Spec.ExternalTrafficPolicy - } + pObj.Spec.ExternalTrafficPolicy = vObj.Spec.ExternalTrafficPolicy - // session affinity - if vObj.Spec.SessionAffinity != pObj.Spec.SessionAffinity { - updated = translator.NewIfNil(updated, pObj) - updated.Spec.SessionAffinity = vObj.Spec.SessionAffinity - } + pObj.Spec.SessionAffinity = vObj.Spec.SessionAffinity - // sessionAffinityConfig - if !equality.Semantic.DeepEqual(vObj.Spec.SessionAffinityConfig, pObj.Spec.SessionAffinityConfig) { - updated = translator.NewIfNil(updated, pObj) - updated.Spec.SessionAffinityConfig = vObj.Spec.SessionAffinityConfig - } + pObj.Spec.SessionAffinityConfig = vObj.Spec.SessionAffinityConfig - // load balancer source ranges - if !equality.Semantic.DeepEqual(vObj.Spec.LoadBalancerSourceRanges, pObj.Spec.LoadBalancerSourceRanges) { - updated = translator.NewIfNil(updated, pObj) - updated.Spec.LoadBalancerSourceRanges = vObj.Spec.LoadBalancerSourceRanges - } + pObj.Spec.LoadBalancerSourceRanges = vObj.Spec.LoadBalancerSourceRanges - // healthCheckNodePort - if vObj.Spec.HealthCheckNodePort != pObj.Spec.HealthCheckNodePort { - updated = translator.NewIfNil(updated, pObj) - updated.Spec.HealthCheckNodePort = vObj.Spec.HealthCheckNodePort - } + pObj.Spec.HealthCheckNodePort = vObj.Spec.HealthCheckNodePort // translate selector - translated := pObj.DeepCopy() - translated.Spec.Selector = translate.Default.TranslateLabels(vObj.Spec.Selector, vObj.Namespace, nil) - if !equality.Semantic.DeepEqual(translated.Spec.Selector, pObj.Spec.Selector) { - updated = translator.NewIfNil(updated, pObj) - updated.Spec.Selector = translated.Spec.Selector - } - - return updated + pObj.Spec.Selector = translate.Default.TranslateLabels(vObj.Spec.Selector, vObj.Namespace, nil) } From d982b9c10fc5bcce3131123bc23c23aa02d4cd6e Mon Sep 17 00:00:00 2001 From: Fabian Kramm Date: Fri, 19 Jul 2024 11:49:46 +0200 Subject: [PATCH 2/2] refactor: patcher for service sync --- pkg/controllers/resources/services/syncer.go | 83 ++++++++++++------- .../resources/services/syncer_test.go | 5 ++ .../resources/services/translate.go | 77 ----------------- pkg/controllers/syncer/context/context.go | 9 ++ 4 files changed, 66 insertions(+), 108 deletions(-) diff --git a/pkg/controllers/resources/services/syncer.go b/pkg/controllers/resources/services/syncer.go index 2bca231d6..632b3a601 100644 --- a/pkg/controllers/resources/services/syncer.go +++ b/pkg/controllers/resources/services/syncer.go @@ -13,6 +13,7 @@ import ( "github.com/loft-sh/vcluster/pkg/mappings" "github.com/loft-sh/vcluster/pkg/patcher" "github.com/loft-sh/vcluster/pkg/specialservices" + "github.com/loft-sh/vcluster/pkg/util/translate" corev1 "k8s.io/api/core/v1" kerrors "k8s.io/apimachinery/pkg/api/errors" utilerrors "k8s.io/apimachinery/pkg/util/errors" @@ -65,17 +66,28 @@ func (s *serviceSyncer) Sync(ctx *synccontext.SyncContext, pObj client.Object, v return ctrl.Result{RequeueAfter: time.Second * 3}, nil } - shouldPatch := false + // check if recreating service is necessary + if vService.Spec.ClusterIP != pService.Spec.ClusterIP { + vService.Spec.ClusterIPs = nil + vService.Spec.ClusterIP = pService.Spec.ClusterIP + ctx.Log.Infof("recreating virtual service %s/%s, because cluster ip differs %s != %s", vService.Namespace, vService.Name, pService.Spec.ClusterIP, vService.Spec.ClusterIP) + + // recreate the new service with the correct cluster ip + err := recreateService(ctx, ctx.VirtualClient, vService) + if err != nil { + ctx.Log.Errorf("error creating virtual service: %s/%s", vService.Namespace, vService.Name) + return ctrl.Result{}, err + } + + return ctrl.Result{Requeue: true}, err + } + + // patch the service patch, err := patcher.NewSyncerPatcher(ctx, pService, vService) if err != nil { return ctrl.Result{}, fmt.Errorf("new syncer patcher: %w", err) } - defer func() { - if !shouldPatch { - return - } - if err := patch.Patch(ctx, pService, vService); err != nil { retErr = utilerrors.NewAggregate([]error{retErr, err}) } @@ -84,29 +96,38 @@ func (s *serviceSyncer) Sync(ctx *synccontext.SyncContext, pObj client.Object, v } }() - // check if backwards update is necessary - newService := s.translateUpdateBackwards(pService, vService) - if newService != nil { - if vService.Spec.ClusterIP != pService.Spec.ClusterIP { - newService.Spec.ClusterIPs = nil - ctx.Log.Infof("recreating virtual service %s/%s, because cluster ip differs %s != %s", vService.Namespace, vService.Name, pService.Spec.ClusterIP, vService.Spec.ClusterIP) - - // recreate the new service with the correct cluster ip - vService, err = recreateService(ctx, ctx.VirtualClient, newService) - if err != nil { - ctx.Log.Errorf("error creating virtual service: %s/%s", vService.Namespace, vService.Name) - } - } else { - newService.DeepCopyInto(vService) - shouldPatch = true - } - return ctrl.Result{Requeue: true}, err - } - shouldPatch = true + // check + sourceService, targetService := synccontext.SyncSourceTarget(ctx, pService, vService) + + // update spec bidirectionally + targetService.Spec.ExternalIPs = sourceService.Spec.ExternalIPs + targetService.Spec.LoadBalancerIP = sourceService.Spec.LoadBalancerIP + targetService.Spec.Ports = sourceService.Spec.Ports + targetService.Spec.PublishNotReadyAddresses = sourceService.Spec.PublishNotReadyAddresses + targetService.Spec.Type = sourceService.Spec.Type + targetService.Spec.ExternalName = sourceService.Spec.ExternalName + targetService.Spec.ExternalTrafficPolicy = sourceService.Spec.ExternalTrafficPolicy + targetService.Spec.SessionAffinity = sourceService.Spec.SessionAffinity + targetService.Spec.SessionAffinityConfig = sourceService.Spec.SessionAffinityConfig + targetService.Spec.LoadBalancerSourceRanges = sourceService.Spec.LoadBalancerSourceRanges + targetService.Spec.HealthCheckNodePort = sourceService.Spec.HealthCheckNodePort + + // update status vService.Status = pService.Status - // forward update - s.translateUpdate(ctx, pService, vService) + // check annotations + _, updatedAnnotations, updatedLabels := s.TranslateMetadataUpdate(ctx, vObj, pObj) + + // remove the ServiceBlockDeletion annotation if it's not needed + if vService.Spec.ClusterIP == pService.Spec.ClusterIP { + delete(updatedAnnotations, ServiceBlockDeletion) + } + + pService.Annotations = updatedAnnotations + pService.Labels = updatedLabels + + // translate selector + pService.Spec.Selector = translate.Default.TranslateLabels(vService.Spec.Selector, vService.Namespace, nil) return ctrl.Result{}, nil } @@ -135,11 +156,11 @@ func (s *serviceSyncer) SyncToVirtual(ctx *synccontext.SyncContext, pObj client. return syncer.DeleteHostObject(ctx, pObj, "virtual object was deleted") } -func recreateService(ctx context.Context, virtualClient client.Client, vService *corev1.Service) (*corev1.Service, error) { +func recreateService(ctx context.Context, virtualClient client.Client, vService *corev1.Service) error { // delete & create with correct ClusterIP err := virtualClient.Delete(ctx, vService) if err != nil && !kerrors.IsNotFound(err) { - return nil, err + return err } // make sure we don't set the resource version during create @@ -153,10 +174,10 @@ func recreateService(ctx context.Context, virtualClient client.Client, vService err = virtualClient.Create(ctx, vService) if err != nil { klog.Errorf("error recreating virtual service: %s/%s: %v", vService.Namespace, vService.Name, err) - return nil, err + return err } - return vService, nil + return nil } var _ syncertypes.Starter = &serviceSyncer{} diff --git a/pkg/controllers/resources/services/syncer_test.go b/pkg/controllers/resources/services/syncer_test.go index 03e356ffb..bf8d9470a 100644 --- a/pkg/controllers/resources/services/syncer_test.go +++ b/pkg/controllers/resources/services/syncer_test.go @@ -125,6 +125,7 @@ func TestSync(t *testing.T) { Namespace: vObjectMeta.Namespace, }, Spec: corev1.ServiceSpec{ + ExternalName: "backwardExternal", ExternalIPs: []string{"123:221:123:221"}, LoadBalancerIP: "123:213:123:213", }, @@ -244,6 +245,7 @@ func TestSync(t *testing.T) { { Name: "test", Port: 123, + NodePort: 567, TargetPort: intstr.FromInt(10), }, }, @@ -332,6 +334,7 @@ func TestSync(t *testing.T) { }, Sync: func(ctx *synccontext.RegisterContext) { syncCtx, syncer := generictesting.FakeStartSyncer(t, ctx, New) + syncCtx.EventSource = synccontext.EventSourceHost _, err := syncer.(*serviceSyncer).Sync(syncCtx, pServicePorts1.DeepCopy(), vServicePorts1.DeepCopy()) assert.NilError(t, err) }, @@ -398,6 +401,7 @@ func TestSync(t *testing.T) { syncCtx, syncer := generictesting.FakeStartSyncer(t, ctx, New) baseService := baseService.DeepCopy() updateBackwardSpecService := updateBackwardSpecService.DeepCopy() + syncCtx.EventSource = synccontext.EventSourceHost _, err := syncer.(*serviceSyncer).Sync(syncCtx, updateBackwardSpecService, baseService) assert.NilError(t, err) @@ -435,6 +439,7 @@ func TestSync(t *testing.T) { err = ctx.PhysicalManager.GetClient().Get(ctx, types.NamespacedName{Namespace: updateBackwardSpecRecreateService.Namespace, Name: updateBackwardSpecRecreateService.Name}, updateBackwardSpecRecreateService) assert.NilError(t, err) + syncCtx.EventSource = synccontext.EventSourceHost baseService.Spec.ExternalName = updateBackwardSpecService.Spec.ExternalName _, err = syncer.(*serviceSyncer).Sync(syncCtx, updateBackwardSpecRecreateService.DeepCopy(), baseService.DeepCopy()) assert.NilError(t, err) diff --git a/pkg/controllers/resources/services/translate.go b/pkg/controllers/resources/services/translate.go index 4f10c1a3e..7aeb7c21b 100644 --- a/pkg/controllers/resources/services/translate.go +++ b/pkg/controllers/resources/services/translate.go @@ -2,12 +2,9 @@ package services import ( "context" - "slices" - "github.com/loft-sh/vcluster/pkg/controllers/syncer/translator" "github.com/loft-sh/vcluster/pkg/util/translate" corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/equality" ) func (s *serviceSyncer) translate(ctx context.Context, vObj *corev1.Service) *corev1.Service { @@ -37,77 +34,3 @@ func StripNodePorts(vObj *corev1.Service) { vObj.Spec.Ports[i].NodePort = 0 } } - -func portsEqual(pObj, vObj *corev1.Service) bool { - pSpec := pObj.Spec.DeepCopy() - vSpec := vObj.Spec.DeepCopy() - for i := range pSpec.Ports { - pSpec.Ports[i].NodePort = 0 - } - for i := range vSpec.Ports { - vSpec.Ports[i].NodePort = 0 - } - return equality.Semantic.DeepEqual(pSpec.Ports, vSpec.Ports) -} - -func (s *serviceSyncer) translateUpdateBackwards(pObj, vObj *corev1.Service) *corev1.Service { - var updated *corev1.Service - - if vObj.Spec.ClusterIP != pObj.Spec.ClusterIP { - updated = translator.NewIfNil(updated, vObj) - updated.Spec.ClusterIP = pObj.Spec.ClusterIP - } - - if !equality.Semantic.DeepEqual(vObj.Spec.ExternalIPs, pObj.Spec.ExternalIPs) { - updated = translator.NewIfNil(updated, vObj) - updated.Spec.ExternalIPs = pObj.Spec.ExternalIPs - } - - if vObj.Spec.LoadBalancerIP != pObj.Spec.LoadBalancerIP { - updated = translator.NewIfNil(updated, vObj) - updated.Spec.LoadBalancerIP = pObj.Spec.LoadBalancerIP - } - - // check if we need to sync node ports from host to virtual - if pObj.Spec.Type == vObj.Spec.Type && portsEqual(pObj, vObj) && !equality.Semantic.DeepEqual(vObj.Spec.Ports, pObj.Spec.Ports) { - updated = translator.NewIfNil(updated, vObj) - updated.Spec.Ports = pObj.Spec.Ports - } - - return updated -} - -func (s *serviceSyncer) translateUpdate(ctx context.Context, pObj, vObj *corev1.Service) { - // check annotations - _, updatedAnnotations, updatedLabels := s.TranslateMetadataUpdate(ctx, vObj, pObj) - // remove the ServiceBlockDeletion annotation if it's not needed - if vObj.Spec.ClusterIP == pObj.Spec.ClusterIP { - delete(updatedAnnotations, ServiceBlockDeletion) - } - pObj.Annotations = updatedAnnotations - pObj.Labels = updatedLabels - - pObj.Spec.Ports = slices.Clone(vObj.Spec.Ports) - - // make sure node ports will be reset here - StripNodePorts(pObj) - - pObj.Spec.PublishNotReadyAddresses = vObj.Spec.PublishNotReadyAddresses - - pObj.Spec.Type = vObj.Spec.Type - - pObj.Spec.ExternalName = vObj.Spec.ExternalName - - pObj.Spec.ExternalTrafficPolicy = vObj.Spec.ExternalTrafficPolicy - - pObj.Spec.SessionAffinity = vObj.Spec.SessionAffinity - - pObj.Spec.SessionAffinityConfig = vObj.Spec.SessionAffinityConfig - - pObj.Spec.LoadBalancerSourceRanges = vObj.Spec.LoadBalancerSourceRanges - - pObj.Spec.HealthCheckNodePort = vObj.Spec.HealthCheckNodePort - - // translate selector - pObj.Spec.Selector = translate.Default.TranslateLabels(vObj.Spec.Selector, vObj.Namespace, nil) -} diff --git a/pkg/controllers/syncer/context/context.go b/pkg/controllers/syncer/context/context.go index a65af0dec..b035cba11 100644 --- a/pkg/controllers/syncer/context/context.go +++ b/pkg/controllers/syncer/context/context.go @@ -31,6 +31,15 @@ type SyncContext struct { IsDelete bool } +func SyncSourceTarget[T any](ctx *SyncContext, pObj, vObj T) (source T, target T) { + if ctx.EventFromHost() { + // sourceObj (Host), targetObj + return pObj, vObj + } + // sourceObj (Virtual), targetObj + return vObj, pObj +} + // Cast returns the given objects as types as well as func Cast[T any](ctx *SyncContext, pObj, vObj client.Object) (physical T, virtual T, source T, target T) { if pObj == nil || vObj == nil {