diff --git a/docs/openstack-cloud-controller-manager/expose-applications-using-loadbalancer-type-service.md b/docs/openstack-cloud-controller-manager/expose-applications-using-loadbalancer-type-service.md index 1751aee984..a74a3b44b3 100644 --- a/docs/openstack-cloud-controller-manager/expose-applications-using-loadbalancer-type-service.md +++ b/docs/openstack-cloud-controller-manager/expose-applications-using-loadbalancer-type-service.md @@ -152,6 +152,14 @@ Request Body: Not supported when `lb-provider=ovn` is configured in openstack-cloud-controller-manager. +- `loadbalancer.openstack.org/lb-method` + + Load balancing algorithm to use when distributed to members. [OpenStack Pool Creation | lb_algorithm](https://docs.openstack.org/api-ref/load-balancer/v2/#create-pool) + + Default value: defined in your OCCM configuration + + Possible values: `ROUND_ROBIN`, `LEAST_CONNECTIONS`, `SOURCE_IP`, `SOURCE_IP_PORT` + - `loadbalancer.openstack.org/timeout-client-data` Frontend client inactivity timeout in milliseconds for the load balancer. diff --git a/pkg/openstack/events.go b/pkg/openstack/events.go index 60dd5cc649..8996cafd2f 100644 --- a/pkg/openstack/events.go +++ b/pkg/openstack/events.go @@ -23,4 +23,5 @@ const ( eventLBAZIgnored = "LoadBalancerAvailabilityZonesIgnored" eventLBFloatingIPSkipped = "LoadBalancerFloatingIPSkipped" eventLBRename = "LoadBalancerRename" + eventLBLbMethodUnknown = "LoadBalancerLbMethodUnknown" ) diff --git a/pkg/openstack/loadbalancer.go b/pkg/openstack/loadbalancer.go index 877db98807..6083fbc955 100644 --- a/pkg/openstack/loadbalancer.go +++ b/pkg/openstack/loadbalancer.go @@ -68,6 +68,7 @@ const ( ServiceAnnotationLoadBalancerClass = "loadbalancer.openstack.org/class" ServiceAnnotationLoadBalancerKeepFloatingIP = "loadbalancer.openstack.org/keep-floatingip" ServiceAnnotationLoadBalancerPortID = "loadbalancer.openstack.org/port-id" + ServiceAnnotationLoadBalancerLbMethod = "loadbalancer.openstack.org/lb-method" ServiceAnnotationLoadBalancerProxyEnabled = "loadbalancer.openstack.org/proxy-protocol" ServiceAnnotationLoadBalancerSubnetID = "loadbalancer.openstack.org/subnet-id" ServiceAnnotationLoadBalancerNetworkID = "loadbalancer.openstack.org/network-id" @@ -125,6 +126,7 @@ type serviceConfig struct { lbPublicSubnetSpec *floatingSubnetSpec nodeSelectors map[string]string keepClientIP bool + poolLbMethod string proxyProtocolVersion *v2pools.Protocol timeoutClientData int timeoutMemberConnect int @@ -900,6 +902,27 @@ func (lbaas *LbaasV2) ensureOctaviaPool(lbID string, name string, listener *list pool = nil } + // If LBMethod changes, update the Pool with the new value + var poolLbMethod string + if svcConf.poolLbMethod != "" { + poolLbMethod = svcConf.poolLbMethod + } else { + // if LBMethod is not defined, fallback on default OCCM's default method + poolLbMethod = lbaas.opts.LBMethod + } + if pool != nil && pool.LBMethod != poolLbMethod { + klog.InfoS("Updating LoadBalancer LBMethod", "poolID", pool.ID, "listenerID", listener.ID, "lbID", lbID) + err = openstackutil.UpdatePool(lbaas.lb, lbID, pool.ID, v2pools.UpdateOpts{LBMethod: v2pools.LBMethod(poolLbMethod)}) + if err != nil { + err = PreserveGopherError(err) + msg := fmt.Sprintf("Error updating LB method for LoadBalancer: %v", err) + klog.Errorf(msg, "poolID", pool.ID, "listenerID", listener.ID, "lbID", lbID) + lbaas.eventRecorder.Eventf(service, corev1.EventTypeWarning, eventLBLbMethodUnknown, msg) + } else { + pool.LBMethod = poolLbMethod + } + } + if pool == nil { createOpt := lbaas.buildPoolCreateOpt(listener.Protocol, service, svcConf, name) createOpt.ListenerID = listener.ID @@ -972,11 +995,18 @@ func (lbaas *LbaasV2) buildPoolCreateOpt(listenerProtocol string, service *corev persistence = &v2pools.SessionPersistence{Type: "SOURCE_IP"} } - lbmethod := v2pools.LBMethod(lbaas.opts.LBMethod) + var lbMethod v2pools.LBMethod + if svcConf.poolLbMethod != "" { + lbMethod = v2pools.LBMethod(svcConf.poolLbMethod) + } else { + // if LBMethod is not defined, fallback on default OCCM's default method + lbMethod = v2pools.LBMethod(lbaas.opts.LBMethod) + } + return v2pools.CreateOpts{ Name: name, Protocol: poolProto, - LBMethod: lbmethod, + LBMethod: lbMethod, Persistence: persistence, } } @@ -1509,6 +1539,7 @@ func (lbaas *LbaasV2) checkService(ctx context.Context, service *corev1.Service, func (lbaas *LbaasV2) makeSvcConf(serviceName string, service *corev1.Service, svcConf *serviceConfig) error { svcConf.connLimit = getIntFromServiceAnnotation(service, ServiceAnnotationLoadBalancerConnLimit, -1) svcConf.lbID = getStringFromServiceAnnotation(service, ServiceAnnotationLoadBalancerID, "") + svcConf.poolLbMethod = getStringFromServiceAnnotation(service, ServiceAnnotationLoadBalancerLbMethod, "") svcConf.supportLBTags = openstackutil.IsOctaviaFeatureSupported(lbaas.lb, openstackutil.OctaviaFeatureTags, lbaas.opts.LBProvider) // Get service node-selector annotations diff --git a/pkg/openstack/loadbalancer_test.go b/pkg/openstack/loadbalancer_test.go index b868009c11..8592885bf4 100644 --- a/pkg/openstack/loadbalancer_test.go +++ b/pkg/openstack/loadbalancer_test.go @@ -1155,6 +1155,29 @@ func Test_buildPoolCreateOpt(t *testing.T) { Persistence: &pools.SessionPersistence{Type: "SOURCE_IP"}, }, }, + { + name: "test for loadbalancing method", + args: args{ + protocol: "TCP", + svcConf: &serviceConfig{ + poolLbMethod: "ROUND_ROBIN", + }, + lbaasV2: &LbaasV2{ + LoadBalancer{ + opts: LoadBalancerOpts{ + LBProvider: "ovn", + LBMethod: "SOURCE_IP_PORT", + }, + }, + }, + service: &corev1.Service{}, + }, + want: pools.CreateOpts{ + Name: "test for loadbalancing method", + Protocol: pools.ProtocolTCP, + LBMethod: "ROUND_ROBIN", + }, + }, } for _, tt := range tests {