From 1366ee336272fa68efee7d9e6ffdb0090bd9aaa0 Mon Sep 17 00:00:00 2001 From: Enrique Llorente Date: Tue, 6 Feb 2024 07:59:12 +0100 Subject: [PATCH] lb: Add selectorless config flag For kubevirt virtualmachines without pod networking with just multus secondary networks the generated endpointslices from the service selector are of no use since they are point to the virt-launcher pod that do not point to any VM. This change add a flag to the lb config so users can skip the lb service selector generation and create their own endpointslices pointing to the secondary network IPs. Signed-off-by: Enrique Llorente --- pkg/provider/cloud.go | 4 ++ pkg/provider/loadbalancer.go | 4 +- pkg/provider/loadbalancer_test.go | 64 ++++++++++++++++++++++++++++++- 3 files changed, 70 insertions(+), 2 deletions(-) diff --git a/pkg/provider/cloud.go b/pkg/provider/cloud.go index fab7da0ba..23400c2d7 100644 --- a/pkg/provider/cloud.go +++ b/pkg/provider/cloud.go @@ -58,6 +58,10 @@ type LoadBalancerConfig struct { // CreationPollTimeout determines how many seconds to wait for the load balancer creation CreationPollTimeout *int `yaml:"creationPollTimeout,omitempty"` + + // Selectorless delegate endpointslices creation on third party by + // skipping service selector creation + Selectorless *bool `yaml:"selectorless,omitempty"` } type InstancesV2Config struct { diff --git a/pkg/provider/loadbalancer.go b/pkg/provider/loadbalancer.go index 702bb3845..56cc5587b 100644 --- a/pkg/provider/loadbalancer.go +++ b/pkg/provider/loadbalancer.go @@ -198,11 +198,13 @@ func (lb *loadbalancer) createLoadBalancerService(ctx context.Context, lbName st }, Spec: corev1.ServiceSpec{ Ports: ports, - Selector: vmiLabels, Type: corev1.ServiceTypeLoadBalancer, ExternalTrafficPolicy: service.Spec.ExternalTrafficPolicy, }, } + if lb.config.Selectorless == nil || !*lb.config.Selectorless { + lbService.Spec.Selector = vmiLabels + } if len(service.Spec.ExternalIPs) > 0 { lbService.Spec.ExternalIPs = service.Spec.ExternalIPs } diff --git a/pkg/provider/loadbalancer_test.go b/pkg/provider/loadbalancer_test.go index ccb73e3bc..c7297b9f0 100644 --- a/pkg/provider/loadbalancer_test.go +++ b/pkg/provider/loadbalancer_test.go @@ -245,7 +245,7 @@ var _ = Describe("LoadBalancer", func() { loadBalancerIP string ) - BeforeAll(func() { + BeforeEach(func() { ctrl, ctx = gomock.WithContext(context.Background(), GinkgoT()) c = mockclient.NewMockClient(ctrl) lb = &loadbalancer{ @@ -402,6 +402,68 @@ var _ = Describe("LoadBalancer", func() { }) + It("Should create new Service without selector if selectorless flag is true", func() { + checkSvcExistErr := notFoundErr + getCount := 1 + port := 30001 + infraServiceExist := generateInfraService( + tenantService, + []corev1.ServicePort{ + {Name: "port1", Protocol: corev1.ProtocolTCP, Port: 80, TargetPort: intstr.IntOrString{Type: intstr.Int, IntVal: int32(port)}}, + }, + ) + infraServiceExist.Status = corev1.ServiceStatus{ + LoadBalancer: corev1.LoadBalancerStatus{ + Ingress: []corev1.LoadBalancerIngress{ + { + IP: loadBalancerIP, + }, + }, + }, + } + + c.EXPECT(). + Get(ctx, client.ObjectKey{Name: "af6ebf1722bb111e9b210d663bd873d9", Namespace: "test"}, gomock.AssignableToTypeOf(&corev1.Service{})). + Return(checkSvcExistErr) + + infraService1 := generateInfraService( + tenantService, + []corev1.ServicePort{ + {Name: "port1", Protocol: corev1.ProtocolTCP, Port: 80, TargetPort: intstr.IntOrString{Type: intstr.Int, IntVal: 30001}}, + }, + ) + infraService1.Spec.Selector = nil + + c.EXPECT().Create(ctx, infraService1) + + for i := 0; i < getCount; i++ { + infraService2 := infraService1.DeepCopy() + if i == getCount-1 { + infraService2.Status = corev1.ServiceStatus{ + LoadBalancer: corev1.LoadBalancerStatus{ + Ingress: []corev1.LoadBalancerIngress{ + { + IP: loadBalancerIP, + }, + }, + }, + } + } + c.EXPECT().Get( + ctx, + client.ObjectKey{Name: "af6ebf1722bb111e9b210d663bd873d9", Namespace: "test"}, + gomock.AssignableToTypeOf(&corev1.Service{}), + ).Do(func(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) { + infraService2.DeepCopyInto(obj.(*corev1.Service)) + }) + } + lb.config.Selectorless = pointer.Bool(true) + lbStatus, err := lb.EnsureLoadBalancer(ctx, clusterName, tenantService, nodes) + Expect(err).To(BeNil()) + Expect(len(lbStatus.Ingress)).Should(Equal(1)) + Expect(lbStatus.Ingress[0].IP).Should(Equal(loadBalancerIP)) + + }) It("Should return an error if service already exist", func() { expectedError := errors.New("Test error - check if service already exist") port := 30001