Skip to content

Commit

Permalink
fix: updateLoadBalancer only when all nodes are initialized
Browse files Browse the repository at this point in the history
  • Loading branch information
Tomy2e committed Feb 11, 2025
1 parent 0cb01e2 commit 5dc909f
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 0 deletions.
24 changes: 24 additions & 0 deletions scaleway/loadbalancers.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (

"golang.org/x/exp/slices"
v1 "k8s.io/api/core/v1"
"k8s.io/cloud-provider/api"
"k8s.io/klog/v2"

scwipam "github.com/scaleway/scaleway-sdk-go/api/ipam/v1"
Expand Down Expand Up @@ -582,6 +583,10 @@ func (l *loadbalancers) updateLoadBalancer(ctx context.Context, loadbalancer *sc
return fmt.Errorf("invalid value for annotation %s: expected boolean", serviceAnnotationLoadBalancerExternallyManaged)
}

if err := nodesInitialized(nodes); err != nil {
return err
}

nodes = filterNodes(service, nodes)
if l.pnID != "" {
respPN, err := l.api.ListLBPrivateNetworks(&scwlb.ZonedAPIListLBPrivateNetworksRequest{
Expand Down Expand Up @@ -1727,3 +1732,22 @@ func hasEqualLoadBalancerStaticIPs(service *v1.Service, lb *scwlb.LB) bool {

return true
}

// nodesInitialized verifies that all nodes are initialized before using them as LoadBalancer targets.
func nodesInitialized(nodes []*v1.Node) error {
for _, node := range nodes {
// If node was created more than 3 minutes ago, we ignore it to
// avoid blocking callers indefinitely.
if time.Since(node.CreationTimestamp.Time) > 3*time.Minute {
continue
}

if slices.ContainsFunc(node.Spec.Taints, func(taint v1.Taint) bool {
return taint.Key == api.TaintExternalCloudProvider
}) {
return fmt.Errorf("node %s is not yet initialized", node.Name)
}
}

return nil
}
79 changes: 79 additions & 0 deletions scaleway/loadbalancers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"github.com/scaleway/scaleway-sdk-go/scw"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/cloud-provider/api"
)

func TestGetValueForPort(t *testing.T) {
Expand Down Expand Up @@ -1401,3 +1402,81 @@ func Test_hasEqualLoadBalancerStaticIPs(t *testing.T) {
})
}
}

func Test_nodesInitialized(t *testing.T) {
type args struct {
nodes []*v1.Node
}
tests := []struct {
name string
args args
wantErr bool
}{
{
name: "node initialized",
args: args{
nodes: []*v1.Node{
{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
},
},
},
},
wantErr: false,
},
{
name: "node not initialized but created 5 minutes ago",
args: args{
nodes: []*v1.Node{
{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
CreationTimestamp: metav1.NewTime(time.Now().Add(-5 * time.Minute)),
},
Spec: v1.NodeSpec{
Taints: []v1.Taint{
{
Key: api.TaintExternalCloudProvider,
Value: "true",
Effect: v1.TaintEffectNoSchedule,
},
},
},
},
},
},
wantErr: false,
},
{
name: "node not initialized, created 10 seconds ago",
args: args{
nodes: []*v1.Node{
{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
CreationTimestamp: metav1.NewTime(time.Now().Add(-10 * time.Second)),
},
Spec: v1.NodeSpec{
Taints: []v1.Taint{
{
Key: api.TaintExternalCloudProvider,
Value: "true",
Effect: v1.TaintEffectNoSchedule,
},
},
},
},
},
},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := nodesInitialized(tt.args.nodes); (err != nil) != tt.wantErr {
t.Errorf("nodesInitialized() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}

0 comments on commit 5dc909f

Please sign in to comment.