Skip to content

Commit 7da7ae9

Browse files
committed
Do not ensure/update LBs if nodes are empty
1 parent aec305f commit 7da7ae9

2 files changed

Lines changed: 64 additions & 0 deletions

File tree

cloud/linode/loadbalancers.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ const (
4949
annLinodeHostnameOnlyIngress = "service.beta.kubernetes.io/linode-loadbalancer-hostname-only-ingress"
5050
)
5151

52+
var (
53+
errNoNodesAvailable = fmt.Errorf("no nodes available for nodebalancer")
54+
)
55+
5256
type lbNotFoundError struct {
5357
serviceNn string
5458
nodeBalancerID int
@@ -212,6 +216,9 @@ func (l *loadbalancers) GetLoadBalancer(ctx context.Context, clusterName string,
212216
//
213217
// EnsureLoadBalancer will not modify service or nodes.
214218
func (l *loadbalancers) EnsureLoadBalancer(ctx context.Context, clusterName string, service *v1.Service, nodes []*v1.Node) (lbStatus *v1.LoadBalancerStatus, err error) {
219+
if len(nodes) == 0 {
220+
return nil, fmt.Errorf("%w: cluster %s, service %s", errNoNodesAvailable, clusterName, getServiceNn(service))
221+
}
215222
ctx = sentry.SetHubOnContext(ctx)
216223
sentry.SetTag(ctx, "cluster_name", clusterName)
217224
sentry.SetTag(ctx, "service", service.Name)
@@ -342,6 +349,9 @@ func (l *loadbalancers) updateNodeBalancer(ctx context.Context, service *v1.Serv
342349

343350
// UpdateLoadBalancer updates the NodeBalancer to have configs that match the Service's ports
344351
func (l *loadbalancers) UpdateLoadBalancer(ctx context.Context, clusterName string, service *v1.Service, nodes []*v1.Node) (err error) {
352+
if len(nodes) == 0 {
353+
return fmt.Errorf("%w: cluster %s, service %s", errNoNodesAvailable, clusterName, getServiceNn(service))
354+
}
345355
ctx = sentry.SetHubOnContext(ctx)
346356
sentry.SetTag(ctx, "cluster_name", clusterName)
347357
sentry.SetTag(ctx, "service", service.Name)

cloud/linode/loadbalancers_test.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package linode
22

33
import (
44
"context"
5+
stderrors "errors"
56
"fmt"
67
"net/http"
78
"net/http/httptest"
@@ -175,6 +176,10 @@ func TestCCMLoadBalancers(t *testing.T) {
175176
name: "Cleanup does not call the API unless Service annotated",
176177
f: testCleanupDoesntCall,
177178
},
179+
{
180+
name: "Update Load Balancer - No Nodes",
181+
f: testUpdateLoadBalancerNoNodes,
182+
},
178183
}
179184

180185
for _, tc := range testCases {
@@ -1550,6 +1555,55 @@ func testCleanupDoesntCall(t *testing.T, client *linodego.Client, fakeAPI *fakeA
15501555
})
15511556
}
15521557

1558+
func testUpdateLoadBalancerNoNodes(t *testing.T, client *linodego.Client, _ *fakeAPI) {
1559+
svc := &v1.Service{
1560+
ObjectMeta: metav1.ObjectMeta{
1561+
Name: randString(10),
1562+
UID: "foobar123",
1563+
Annotations: map[string]string{},
1564+
},
1565+
Spec: v1.ServiceSpec{
1566+
Ports: []v1.ServicePort{
1567+
{
1568+
Name: randString(10),
1569+
Protocol: "http",
1570+
Port: int32(80),
1571+
NodePort: int32(8080),
1572+
},
1573+
},
1574+
},
1575+
}
1576+
1577+
lb := &loadbalancers{client, "us-west", nil}
1578+
defer lb.EnsureLoadBalancerDeleted(context.TODO(), "linodelb", svc)
1579+
1580+
fakeClientset := fake.NewSimpleClientset()
1581+
lb.kubeClient = fakeClientset
1582+
1583+
nodeBalancer, err := client.CreateNodeBalancer(context.TODO(), linodego.NodeBalancerCreateOptions{
1584+
Region: lb.zone,
1585+
})
1586+
if err != nil {
1587+
t.Fatalf("failed to create NodeBalancer: %s", err)
1588+
}
1589+
svc.Status.LoadBalancer = *makeLoadBalancerStatus(svc, nodeBalancer)
1590+
stubService(fakeClientset, svc)
1591+
svc.ObjectMeta.SetAnnotations(map[string]string{
1592+
annLinodeNodeBalancerID: strconv.Itoa(nodeBalancer.ID),
1593+
})
1594+
1595+
// setup done, test ensure/update
1596+
nodes := []*v1.Node{}
1597+
1598+
if _, err = lb.EnsureLoadBalancer(context.TODO(), "linodelb", svc, nodes); !stderrors.Is(err, errNoNodesAvailable) {
1599+
t.Errorf("EnsureLoadBalancer should return %v, got %v", errNoNodesAvailable, err)
1600+
}
1601+
1602+
if err := lb.UpdateLoadBalancer(context.TODO(), "linodelb", svc, nodes); !stderrors.Is(err, errNoNodesAvailable) {
1603+
t.Errorf("UpdateLoadBalancer should return %v, got %v", errNoNodesAvailable, err)
1604+
}
1605+
}
1606+
15531607
func testGetNodeBalancerForServiceIDDoesNotExist(t *testing.T, client *linodego.Client, _ *fakeAPI) {
15541608
lb := &loadbalancers{client, "us-west", nil}
15551609
bogusNodeBalancerID := "123456"

0 commit comments

Comments
 (0)