Skip to content

Commit 7ae7b0c

Browse files
committed
lbaas: add a new batch pools members update endpoint support
1 parent e862efc commit 7ae7b0c

5 files changed

Lines changed: 94 additions & 3 deletions

File tree

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ require (
4444

4545
// the below fixes the "go list -m all" execution
4646
replace (
47+
github.com/gophercloud/gophercloud/v2 => github.com/kayrus/gophercloud/v2 v2.10.1-0.20260112125525-25600003eb41
4748
k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.34.2
4849
k8s.io/cri-client => k8s.io/cri-client v0.34.2
4950
k8s.io/dynamic-resource-allocation => k8s.io/dynamic-resource-allocation v0.34.2

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,6 @@ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
176176
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
177177
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
178178
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
179-
github.com/gophercloud/gophercloud/v2 v2.8.0 h1:of2+8tT6+FbEYHfYC8GBu8TXJNsXYSNm9KuvpX7Neqo=
180-
github.com/gophercloud/gophercloud/v2 v2.8.0/go.mod h1:Ki/ILhYZr/5EPebrPL9Ej+tUg4lqx71/YH2JWVeU+Qk=
181179
github.com/gophercloud/utils/v2 v2.0.0-20250930154317-576cdf6142a7 h1:y0/17y47lq1dD97qEqbbvjsMF8PzLmqmD839aOePRuc=
182180
github.com/gophercloud/utils/v2 v2.0.0-20250930154317-576cdf6142a7/go.mod h1:dVCIqYUB0Q8JDbMZaReU6BkAQAS9j3l3Kyc7GuSIztU=
183181
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo=
@@ -203,6 +201,8 @@ github.com/joshdk/go-junit v1.0.0 h1:S86cUKIdwBHWwA6xCmFlf3RTLfVXYQfvanM5Uh+K6GE
203201
github.com/joshdk/go-junit v1.0.0/go.mod h1:TiiV0PqkaNfFXjEiyjWM3XXrhVyCa1K4Zfga6W52ung=
204202
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
205203
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
204+
github.com/kayrus/gophercloud/v2 v2.10.1-0.20260112125525-25600003eb41 h1:xOyZk+OmT61jjR2srqEY3QVy8Fp931Wl0RMYlLID9C0=
205+
github.com/kayrus/gophercloud/v2 v2.10.1-0.20260112125525-25600003eb41/go.mod h1:Ki/ILhYZr/5EPebrPL9Ej+tUg4lqx71/YH2JWVeU+Qk=
206206
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
207207
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
208208
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=

pkg/openstack/loadbalancer.go

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ const (
8989
ServiceAnnotationLoadBalancerHealthMonitorMaxRetriesDown = "loadbalancer.openstack.org/health-monitor-max-retries-down"
9090
ServiceAnnotationLoadBalancerLoadbalancerHostname = "loadbalancer.openstack.org/hostname"
9191
ServiceAnnotationLoadBalancerAddress = "loadbalancer.openstack.org/load-balancer-address"
92+
ServiceAnnotationLoadBalancerBatchPoolsMembersUpdate = "loadbalancer.openstack.org/batch-pools-members-update"
9293
// revive:disable:var-naming
9394
ServiceAnnotationTlsContainerRef = "loadbalancer.openstack.org/default-tls-container-ref"
9495
// revive:enable:var-naming
@@ -959,14 +960,18 @@ func (lbaas *LbaasV2) ensureOctaviaPool(ctx context.Context, lbID string, name s
959960
return nil, err
960961
}
961962

962-
if !curMembers.Equal(newMembers) {
963+
batchPoolsMembersUpdate := getBoolFromServiceAnnotation(service, ServiceAnnotationLoadBalancerBatchPoolsMembersUpdate, lbaas.opts.BatchPoolsMembersUpdate)
964+
if !curMembers.Equal(newMembers) && !batchPoolsMembersUpdate {
963965
klog.V(2).Infof("Updating %d members for pool %s", len(members), pool.ID)
964966
if err := openstackutil.BatchUpdatePoolMembers(ctx, lbaas.lb, lbID, pool.ID, members); err != nil {
965967
return nil, err
966968
}
967969
klog.V(2).Infof("Successfully updated %d members for pool %s", len(members), pool.ID)
968970
}
969971

972+
// set the updated members to the pool for further batch update
973+
pool.Members = batchUpdateMemberOptsToMembers(members)
974+
970975
return pool, nil
971976
}
972977

@@ -1050,6 +1055,20 @@ func (lbaas *LbaasV2) buildBatchUpdateMemberOpts(ctx context.Context, port corev
10501055
return members, newMembers, nil
10511056
}
10521057

1058+
func batchUpdateMemberOptsToMembers(opts []v2pools.BatchUpdateMemberOpts) []v2pools.Member {
1059+
members := make([]v2pools.Member, len(opts))
1060+
for i := range opts {
1061+
members[i] = v2pools.Member{
1062+
Address: opts[i].Address,
1063+
ProtocolPort: opts[i].ProtocolPort,
1064+
Name: ptr.Deref(opts[i].Name, ""),
1065+
SubnetID: ptr.Deref(opts[i].SubnetID, ""),
1066+
MonitorPort: ptr.Deref(opts[i].MonitorPort, 0),
1067+
}
1068+
}
1069+
return members
1070+
}
1071+
10531072
func (lbaas *LbaasV2) buildCreateMemberOpts(ctx context.Context, port corev1.ServicePort, nodes []*corev1.Node, svcConf *serviceConfig) ([]v2pools.CreateMemberOpts, sets.Set[string], error) {
10541073
batchUpdateMemberOpts, newMembers, err := lbaas.buildBatchUpdateMemberOpts(ctx, port, nodes, svcConf)
10551074
if err != nil {
@@ -1783,6 +1802,8 @@ func (lbaas *LbaasV2) ensureOctaviaLoadBalancer(ctx context.Context, clusterName
17831802
return nil, err
17841803
}
17851804

1805+
// a list of pools to update
1806+
pools := make([]v2pools.Pool, 0, len(service.Spec.Ports))
17861807
for portIndex, port := range service.Spec.Ports {
17871808
listener, err := lbaas.ensureOctaviaListener(ctx, loadbalancer.ID, cpoutil.Sprintf255(listenerFormat, portIndex, lbName), curListenerMapping, port, svcConf)
17881809
if err != nil {
@@ -1793,6 +1814,7 @@ func (lbaas *LbaasV2) ensureOctaviaLoadBalancer(ctx context.Context, clusterName
17931814
if err != nil {
17941815
return nil, err
17951816
}
1817+
pools = append(pools, *pool)
17961818

17971819
if err := lbaas.ensureOctaviaHealthMonitor(ctx, loadbalancer.ID, cpoutil.Sprintf255(monitorFormat, portIndex, lbName), pool, port, svcConf); err != nil {
17981820
return nil, err
@@ -1804,6 +1826,17 @@ func (lbaas *LbaasV2) ensureOctaviaLoadBalancer(ctx context.Context, clusterName
18041826
curListeners = popListener(curListeners, listener.ID)
18051827
}
18061828

1829+
batchPoolsMembersUpdate := getBoolFromServiceAnnotation(service, ServiceAnnotationLoadBalancerBatchPoolsMembersUpdate, lbaas.opts.BatchPoolsMembersUpdate)
1830+
if batchPoolsMembersUpdate {
1831+
err := openstackutil.BatchUpdatePoolsMembers(ctx, lbaas.lb, loadbalancer.ID, pools)
1832+
if err != nil {
1833+
err = PreserveGopherError(err)
1834+
msg := fmt.Sprintf("Error updating batch pools members for LoadBalancer: %v", err)
1835+
klog.Errorf(msg, "lbID", loadbalancer.ID)
1836+
return nil, err
1837+
}
1838+
}
1839+
18071840
// Deal with the remaining listeners, delete the listener if it was created by this Service previously.
18081841
if err := lbaas.deleteOctaviaListeners(ctx, loadbalancer.ID, curListeners, isLBOwner, lbName); err != nil {
18091842
return nil, err
@@ -1935,6 +1968,9 @@ func (lbaas *LbaasV2) updateOctaviaLoadBalancer(ctx context.Context, clusterName
19351968
lbListeners[key] = l
19361969
}
19371970

1971+
// a list of pools to update
1972+
pools := make([]v2pools.Pool, 0, len(service.Spec.Ports))
1973+
19381974
// Update pool members for each listener.
19391975
for portIndex, port := range service.Spec.Ports {
19401976
proto := getListenerProtocol(port.Protocol, svcConf)
@@ -1950,13 +1986,25 @@ func (lbaas *LbaasV2) updateOctaviaLoadBalancer(ctx context.Context, clusterName
19501986
if err != nil {
19511987
return err
19521988
}
1989+
pools = append(pools, *pool)
19531990

19541991
err = lbaas.ensureOctaviaHealthMonitor(ctx, loadbalancer.ID, cpoutil.Sprintf255(monitorFormat, portIndex, loadbalancer.Name), pool, port, svcConf)
19551992
if err != nil {
19561993
return err
19571994
}
19581995
}
19591996

1997+
batchPoolsMembersUpdate := getBoolFromServiceAnnotation(service, ServiceAnnotationLoadBalancerBatchPoolsMembersUpdate, lbaas.opts.BatchPoolsMembersUpdate)
1998+
if batchPoolsMembersUpdate {
1999+
err := openstackutil.BatchUpdatePoolsMembers(ctx, lbaas.lb, loadbalancer.ID, pools)
2000+
if err != nil {
2001+
err = PreserveGopherError(err)
2002+
msg := fmt.Sprintf("Error updating batch pools members for LoadBalancer: %v", err)
2003+
klog.Errorf(msg, "lbID", loadbalancer.ID)
2004+
return err
2005+
}
2006+
}
2007+
19602008
if lbaas.opts.ManageSecurityGroups {
19612009
err := lbaas.ensureAndUpdateOctaviaSecurityGroup(ctx, clusterName, service, filteredNodes, svcConf)
19622010
if err != nil {

pkg/openstack/openstack.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ type LoadBalancerOpts struct {
120120
MaxSharedLB int `gcfg:"max-shared-lb"` // Number of Services in maximum can share a single load balancer. Default 2
121121
ContainerStore string `gcfg:"container-store"` // Used to specify the store of the tls-container-ref
122122
ProviderRequiresSerialAPICalls bool `gcfg:"provider-requires-serial-api-calls"` // default false, the provider supports the "bulk update" API call
123+
BatchPoolsMembersUpdate bool `gcfg:"batch-pools-members-update"` // default false, the controller will update all pools members in batch when possible
123124
// revive:disable:var-naming
124125
TlsContainerRef string `gcfg:"default-tls-container-ref"` // reference to a tls container
125126
// revive:enable:var-naming

pkg/util/openstack/loadbalancer.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,47 @@ func BatchUpdatePoolMembers(ctx context.Context, client *gophercloud.ServiceClie
603603
return nil
604604
}
605605

606+
// BatchUpdatePoolsMembers
607+
func BatchUpdatePoolsMembers(ctx context.Context, client *gophercloud.ServiceClient, lbID string, newPools []pools.Pool) error {
608+
mc := metrics.NewMetricContext("loadbalancer_pools_members", "update")
609+
610+
opts := make([]pools.BatchUpdateMemberOpts, 0, len(newPools)*len(newPools[0].Members))
611+
for _, p := range newPools {
612+
for _, m := range p.Members {
613+
var name, subnetID *string
614+
if m.Name != "" {
615+
name = &m.Name
616+
}
617+
if m.SubnetID != "" {
618+
subnetID = &m.SubnetID
619+
}
620+
var monitorPort *int
621+
if m.MonitorPort > 0 {
622+
monitorPort = &m.MonitorPort
623+
}
624+
opts = append(opts, pools.BatchUpdateMemberOpts{
625+
PoolID: p.ID,
626+
Address: m.Address,
627+
ProtocolPort: m.ProtocolPort,
628+
Name: name,
629+
SubnetID: subnetID,
630+
MonitorPort: monitorPort,
631+
})
632+
}
633+
}
634+
635+
err := pools.BatchUpdatePoolsMembers(ctx, client, opts).ExtractErr()
636+
if mc.ObserveRequest(err) != nil {
637+
return err
638+
}
639+
640+
if _, err := WaitActiveAndGetLoadBalancer(ctx, client, lbID); err != nil {
641+
return fmt.Errorf("failed to wait for load balancer %s ACTIVE after updating pools members: %v", lbID, err)
642+
}
643+
644+
return nil
645+
}
646+
606647
// GetL7policies retrieves all l7 policies for the given listener.
607648
func GetL7policies(ctx context.Context, client *gophercloud.ServiceClient, listenerID string) ([]l7policies.L7Policy, error) {
608649
var policies []l7policies.L7Policy

0 commit comments

Comments
 (0)