Skip to content

Commit cee9a0e

Browse files
author
yujiel
committed
Fixed the issue where the service could not change from Loadbalancer to ClusterIP/NodePort
Signed-off-by: yujiel <yujiel@ebtech.com>
1 parent 6f5d651 commit cee9a0e

File tree

2 files changed

+200
-3
lines changed

2 files changed

+200
-3
lines changed

pkg/controllers/resources/services/syncer.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ func (s *serviceSyncer) Sync(ctx *synccontext.SyncContext, event *synccontext.Sy
191191
)
192192

193193
// update status
194+
ensureLoadBalancerStatus(event.Host)
194195
event.Virtual.Status = event.Host.Status
195196

196197
// bi-directional sync of annotations and labels
@@ -299,3 +300,17 @@ func TranslateServicePorts(ports []corev1.ServicePort) []corev1.ServicePort {
299300

300301
return retPorts
301302
}
303+
304+
// ensureLoadBalancerStatus removes any LoadBalancer-related fields from the Service
305+
// if it is of type ClusterIP.
306+
//
307+
// This is necessary to ensure consistency when syncing services from a virtual
308+
// cluster to the host cluster. ClusterIP services should not carry LoadBalancer
309+
// settings such as LoadBalancerIP or Status.LoadBalancer.Ingress, which are
310+
// specific to LoadBalancer-type services and can cause incorrect behavior if retained.
311+
func ensureLoadBalancerStatus(pObj *corev1.Service) {
312+
if pObj.Spec.Type != corev1.ServiceTypeLoadBalancer {
313+
pObj.Spec.LoadBalancerIP = ""
314+
pObj.Status.LoadBalancer.Ingress = make([]corev1.LoadBalancerIngress, 0)
315+
}
316+
}

pkg/controllers/resources/services/syncer_test.go

Lines changed: 185 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,19 @@ func TestSync(t *testing.T) {
136136
},
137137
Spec: updateBackwardRecreateSpec,
138138
}
139+
updateBackwardSpecRecreateServiceExpected := &corev1.Service{
140+
ObjectMeta: metav1.ObjectMeta{
141+
Name: pObjectMeta.Name,
142+
Namespace: pObjectMeta.Namespace,
143+
Labels: pObjectMeta.Labels,
144+
Annotations: pObjectMeta.Annotations,
145+
},
146+
Spec: corev1.ServiceSpec{
147+
ClusterIP: "123:123:123:123",
148+
ExternalName: updateBackwardSpec.ExternalName,
149+
ExternalIPs: updateBackwardSpec.ExternalIPs,
150+
},
151+
}
139152
updatedBackwardSpecRecreateService := &corev1.Service{
140153
ObjectMeta: metav1.ObjectMeta{
141154
Name: vObjectMeta.Name,
@@ -162,9 +175,17 @@ func TestSync(t *testing.T) {
162175
ObjectMeta: pObjectMeta,
163176
Status: updateBackwardStatus,
164177
}
178+
updateBackwardStatusServiceExpected := &corev1.Service{
179+
ObjectMeta: pObjectMeta,
180+
Status: corev1.ServiceStatus{
181+
LoadBalancer: corev1.LoadBalancerStatus{},
182+
},
183+
}
165184
updatedBackwardStatusService := &corev1.Service{
166185
ObjectMeta: vObjectMeta,
167-
Status: updateBackwardStatus,
186+
Status: corev1.ServiceStatus{
187+
LoadBalancer: corev1.LoadBalancerStatus{},
188+
},
168189
}
169190
kubernetesWithClusterIPService := &corev1.Service{
170191
ObjectMeta: vKubernetesObjectMeta,
@@ -307,6 +328,127 @@ func TestSync(t *testing.T) {
307328
Ports: vServiceNodePortFromExternal.Spec.Ports,
308329
},
309330
}
331+
vServiceNodePortFromLoadBalancer := &corev1.Service{
332+
ObjectMeta: vObjectMeta,
333+
Spec: corev1.ServiceSpec{
334+
Selector: map[string]string{selectorKey: "test-key"},
335+
Type: corev1.ServiceTypeNodePort,
336+
Ports: []corev1.ServicePort{
337+
{
338+
Name: "http",
339+
Port: 8080,
340+
},
341+
},
342+
},
343+
}
344+
vServiceNodePortFromLoadBalancerBefore := &corev1.Service{
345+
ObjectMeta: vObjectMeta,
346+
Spec: corev1.ServiceSpec{
347+
Selector: map[string]string{selectorKey: "test-key"},
348+
Type: corev1.ServiceTypeLoadBalancer,
349+
Ports: []corev1.ServicePort{
350+
{
351+
Name: "http",
352+
Port: 8080,
353+
},
354+
},
355+
},
356+
Status: corev1.ServiceStatus{
357+
LoadBalancer: corev1.LoadBalancerStatus{
358+
Ingress: []corev1.LoadBalancerIngress{
359+
{
360+
IP: "1.2.3.4",
361+
},
362+
},
363+
},
364+
},
365+
}
366+
pServiceLoadBalancer := &corev1.Service{
367+
ObjectMeta: pObjectMeta,
368+
Spec: corev1.ServiceSpec{
369+
Selector: map[string]string{
370+
translate.HostLabel(selectorKey): vServiceNodePortFromExternal.Spec.Selector[selectorKey],
371+
translate.NamespaceLabel: vServiceNodePortFromExternal.Namespace,
372+
translate.MarkerLabel: translate.VClusterName,
373+
},
374+
Type: corev1.ServiceTypeClusterIP,
375+
Ports: []corev1.ServicePort{
376+
{
377+
Name: "http",
378+
Port: 8080,
379+
},
380+
},
381+
},
382+
}
383+
pServiceNodePortFromLoadBalancer := &corev1.Service{
384+
ObjectMeta: pObjectMeta,
385+
Spec: corev1.ServiceSpec{
386+
Selector: map[string]string{
387+
translate.HostLabel(selectorKey): vServiceNodePortFromLoadBalancer.Spec.Selector[selectorKey],
388+
translate.NamespaceLabel: vServiceNodePortFromLoadBalancer.Namespace,
389+
translate.MarkerLabel: translate.VClusterName,
390+
},
391+
Type: corev1.ServiceTypeNodePort,
392+
Ports: []corev1.ServicePort{
393+
{
394+
Name: "http",
395+
Port: 8080,
396+
},
397+
},
398+
},
399+
}
400+
vServiceClusterIPFromLoadBalancer := &corev1.Service{
401+
ObjectMeta: vObjectMeta,
402+
Spec: corev1.ServiceSpec{
403+
Selector: map[string]string{selectorKey: "test-key"},
404+
Type: corev1.ServiceTypeClusterIP,
405+
Ports: []corev1.ServicePort{
406+
{
407+
Name: "http",
408+
Port: 8080,
409+
},
410+
},
411+
},
412+
}
413+
vServiceClusterIPFromLoadBalancerBefore := &corev1.Service{
414+
ObjectMeta: vObjectMeta,
415+
Spec: corev1.ServiceSpec{
416+
Selector: map[string]string{selectorKey: "test-key"},
417+
Type: corev1.ServiceTypeLoadBalancer,
418+
Ports: []corev1.ServicePort{
419+
{
420+
Name: "http",
421+
Port: 8080,
422+
},
423+
},
424+
},
425+
Status: corev1.ServiceStatus{
426+
LoadBalancer: corev1.LoadBalancerStatus{
427+
Ingress: []corev1.LoadBalancerIngress{
428+
{
429+
IP: "1.2.3.4",
430+
},
431+
},
432+
},
433+
},
434+
}
435+
pServiceClusterIPFromLoadBalancer := &corev1.Service{
436+
ObjectMeta: pObjectMeta,
437+
Spec: corev1.ServiceSpec{
438+
Type: corev1.ServiceTypeClusterIP,
439+
Selector: map[string]string{
440+
translate.HostLabel(selectorKey): vServiceClusterIPFromLoadBalancer.Spec.Selector[selectorKey],
441+
translate.NamespaceLabel: vServiceClusterIPFromLoadBalancer.Namespace,
442+
translate.MarkerLabel: translate.VClusterName,
443+
},
444+
Ports: []corev1.ServicePort{
445+
{
446+
Name: "http",
447+
Port: 8080,
448+
},
449+
},
450+
},
451+
}
310452

311453
tests := []*syncertesting.SyncTest{
312454
{
@@ -439,7 +581,7 @@ func TestSync(t *testing.T) {
439581
corev1.SchemeGroupVersion.WithKind("Service"): {updatedBackwardSpecRecreateService.DeepCopy()},
440582
},
441583
ExpectedPhysicalState: map[schema.GroupVersionKind][]runtime.Object{
442-
corev1.SchemeGroupVersion.WithKind("Service"): {updateBackwardSpecRecreateService.DeepCopy()},
584+
corev1.SchemeGroupVersion.WithKind("Service"): {updateBackwardSpecRecreateServiceExpected.DeepCopy()},
443585
},
444586
Sync: func(ctx *synccontext.RegisterContext) {
445587
syncCtx, syncer := syncertesting.FakeStartSyncer(t, ctx, New)
@@ -468,7 +610,7 @@ func TestSync(t *testing.T) {
468610
corev1.SchemeGroupVersion.WithKind("Service"): {updatedBackwardStatusService.DeepCopy()},
469611
},
470612
ExpectedPhysicalState: map[schema.GroupVersionKind][]runtime.Object{
471-
corev1.SchemeGroupVersion.WithKind("Service"): {updateBackwardStatusService.DeepCopy()},
613+
corev1.SchemeGroupVersion.WithKind("Service"): {updateBackwardStatusServiceExpected.DeepCopy()},
472614
},
473615
Sync: func(ctx *synccontext.RegisterContext) {
474616
syncCtx, syncer := syncertesting.FakeStartSyncer(t, ctx, New)
@@ -609,6 +751,46 @@ func TestSync(t *testing.T) {
609751
assert.NilError(t, err)
610752
},
611753
},
754+
{
755+
Name: "Sync kubernetes service change type LoadBalancer to NodePort",
756+
InitialVirtualState: []runtime.Object{vServiceNodePortFromLoadBalancer.DeepCopy()},
757+
InitialPhysicalState: []runtime.Object{pServiceLoadBalancer.DeepCopy()},
758+
ExpectedVirtualState: map[schema.GroupVersionKind][]runtime.Object{
759+
corev1.SchemeGroupVersion.WithKind("Service"): {vServiceNodePortFromLoadBalancer.DeepCopy()},
760+
},
761+
ExpectedPhysicalState: map[schema.GroupVersionKind][]runtime.Object{
762+
corev1.SchemeGroupVersion.WithKind("Service"): {pServiceNodePortFromLoadBalancer.DeepCopy()},
763+
},
764+
Sync: func(ctx *synccontext.RegisterContext) {
765+
syncCtx, syncer := syncertesting.FakeStartSyncer(t, ctx, New)
766+
pObjOld := pServiceLoadBalancer.DeepCopy()
767+
pObjNew := pServiceLoadBalancer.DeepCopy()
768+
vObjOld := vServiceNodePortFromLoadBalancerBefore.DeepCopy()
769+
vObjNew := vServiceNodePortFromLoadBalancer.DeepCopy()
770+
_, err := syncer.(*serviceSyncer).Sync(syncCtx, synccontext.NewSyncEventWithOld(pObjOld, pObjNew, vObjOld, vObjNew))
771+
assert.NilError(t, err)
772+
},
773+
},
774+
{
775+
Name: "Sync kubernetes service change type LoadBalancer to ClusterIP",
776+
InitialVirtualState: []runtime.Object{vServiceClusterIPFromLoadBalancer.DeepCopy()},
777+
InitialPhysicalState: []runtime.Object{pServiceLoadBalancer.DeepCopy()},
778+
ExpectedVirtualState: map[schema.GroupVersionKind][]runtime.Object{
779+
corev1.SchemeGroupVersion.WithKind("Service"): {vServiceClusterIPFromLoadBalancer.DeepCopy()},
780+
},
781+
ExpectedPhysicalState: map[schema.GroupVersionKind][]runtime.Object{
782+
corev1.SchemeGroupVersion.WithKind("Service"): {pServiceClusterIPFromLoadBalancer.DeepCopy()},
783+
},
784+
Sync: func(ctx *synccontext.RegisterContext) {
785+
syncCtx, syncer := syncertesting.FakeStartSyncer(t, ctx, New)
786+
pObjOld := pServiceLoadBalancer.DeepCopy()
787+
pObjNew := pServiceLoadBalancer.DeepCopy()
788+
vObjOld := vServiceClusterIPFromLoadBalancerBefore.DeepCopy()
789+
vObjNew := vServiceClusterIPFromLoadBalancer.DeepCopy()
790+
_, err := syncer.(*serviceSyncer).Sync(syncCtx, synccontext.NewSyncEventWithOld(pObjOld, pObjNew, vObjOld, vObjNew))
791+
assert.NilError(t, err)
792+
},
793+
},
612794
}
613795
syncertesting.RunTests(t, tests)
614796
}

0 commit comments

Comments
 (0)