diff --git a/pkg/ingress/config/config.go b/pkg/ingress/config/config.go index 8658fae925..8a5e96e602 100644 --- a/pkg/ingress/config/config.go +++ b/pkg/ingress/config/config.go @@ -62,4 +62,9 @@ type octaviaConfig struct { // the load balancer instead of the bulk update API call. // Default is false. ProviderRequiresSerialAPICalls bool `mapstructure:"provider-requires-serial-api-calls"` + + // (Optional) If the provider requires nodeports for accessing the nodes or allows usage + // of `allocateLoadBalancerNodePorts=false` + // Default is true. + ProviderRequiresNodeports bool `mapstructure:"provider-requires-nodeports"` } diff --git a/pkg/openstack/loadbalancer.go b/pkg/openstack/loadbalancer.go index c67ba1f1b4..9930baf0eb 100644 --- a/pkg/openstack/loadbalancer.go +++ b/pkg/openstack/loadbalancer.go @@ -1033,10 +1033,21 @@ func (lbaas *LbaasV2) buildBatchUpdateMemberOpts(ctx context.Context, port corev memberSubnetID = nil } - if port.NodePort != 0 { // It's 0 when AllocateLoadBalancerNodePorts=False + var protoPort int32 + if !lbaas.opts.ProviderRequiresNodeports { + protoPort = port.Port + } else { + if port.NodePort != 0 { // It's 0 when AllocateLoadBalancerNodePorts=False + protoPort = port.NodePort + } + } + + // protoPort set when provider doesn't require nodePorts (and e.g. AllocateLoadBalancerNodePorts=false) + // or when NodePort is set + if protoPort > 0 { member := v2pools.BatchUpdateMemberOpts{ Address: addr, - ProtocolPort: int(port.NodePort), + ProtocolPort: int(protoPort), Name: &node.Name, SubnetID: memberSubnetID, } diff --git a/pkg/openstack/loadbalancer_test.go b/pkg/openstack/loadbalancer_test.go index 27304a45ad..e56ab5edc3 100644 --- a/pkg/openstack/loadbalancer_test.go +++ b/pkg/openstack/loadbalancer_test.go @@ -3,11 +3,12 @@ package openstack import ( "context" "fmt" - "k8s.io/utils/ptr" "reflect" "sort" "testing" + "k8s.io/utils/ptr" + "github.com/gophercloud/gophercloud/v2" "github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/listeners" v2monitors "github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/monitors" @@ -1905,11 +1906,17 @@ func TestBuildBatchUpdateMemberOpts(t *testing.T) { }, }, } + + defaultLBaasOpts := LoadBalancerOpts{ + ProviderRequiresNodeports: true, + } + testCases := []struct { name string nodes []*corev1.Node port corev1.ServicePort svcConf *serviceConfig + lbOpts *LoadBalancerOpts expectedLen int expectedNewMembersCount int }{ @@ -1925,6 +1932,21 @@ func TestBuildBatchUpdateMemberOpts(t *testing.T) { expectedLen: 0, expectedNewMembersCount: 0, }, + { + name: "NodesPortequalszero, providerRequiresNodeports=false", + nodes: []*corev1.Node{node1, node2}, + port: corev1.ServicePort{NodePort: 0, Port: 80}, + svcConf: &serviceConfig{ + preferredIPFamily: corev1.IPv4Protocol, + lbMemberSubnetID: "subnet-12345-test", + healthCheckNodePort: 8081, + }, + lbOpts: &LoadBalancerOpts{ + ProviderRequiresNodeports: false, + }, + expectedLen: 2, + expectedNewMembersCount: 2, + }, { name: "Valid nodes, canUseHTTPMonitor=false", nodes: []*corev1.Node{node1, node2}, @@ -1987,7 +2009,15 @@ func TestBuildBatchUpdateMemberOpts(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - lbaas := &LbaasV2{} + lbaas := &LbaasV2{ + LoadBalancer: LoadBalancer{ + opts: defaultLBaasOpts, + }, + } + // overwrite default options + if tc.lbOpts != nil { + lbaas.opts = *tc.lbOpts + } members, newMembers, err := lbaas.buildBatchUpdateMemberOpts(context.TODO(), tc.port, tc.nodes, tc.svcConf) assert.Len(t, members, tc.expectedLen) assert.NoError(t, err) diff --git a/pkg/openstack/openstack.go b/pkg/openstack/openstack.go index ac07d50345..cdca28d407 100644 --- a/pkg/openstack/openstack.go +++ b/pkg/openstack/openstack.go @@ -120,6 +120,7 @@ type LoadBalancerOpts struct { MaxSharedLB int `gcfg:"max-shared-lb"` // Number of Services in maximum can share a single load balancer. Default 2 ContainerStore string `gcfg:"container-store"` // Used to specify the store of the tls-container-ref ProviderRequiresSerialAPICalls bool `gcfg:"provider-requires-serial-api-calls"` // default false, the provider supports the "bulk update" API call + ProviderRequiresNodeports bool `gcfg:"provider-requires-nodeports"` // default true, the provider requires nodeports for accessing nodes // revive:disable:var-naming TlsContainerRef string `gcfg:"default-tls-container-ref"` // reference to a tls container // revive:enable:var-naming @@ -227,6 +228,7 @@ func ReadConfig(config io.Reader) (Config, error) { cfg.LoadBalancer.ContainerStore = "barbican" cfg.LoadBalancer.MaxSharedLB = 2 cfg.LoadBalancer.ProviderRequiresSerialAPICalls = false + cfg.LoadBalancer.ProviderRequiresNodeports = true err := gcfg.FatalOnly(gcfg.ReadInto(&cfg, config)) if err != nil {