Skip to content

Commit fc4ad36

Browse files
authored
Merge pull request #139 from okokes-akamai/empty_nodes
Do not ensure/update LBs if nodes are empty
2 parents 1e53829 + 40b79e3 commit fc4ad36

File tree

2 files changed

+69
-1
lines changed

2 files changed

+69
-1
lines changed

cloud/linode/loadbalancers.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package linode
33
import (
44
"context"
55
"encoding/json"
6+
"errors"
67
"fmt"
78
"net/http"
89
"os"
@@ -51,6 +52,10 @@ const (
5152
annLinodeLoadBalancerTags = "service.beta.kubernetes.io/linode-loadbalancer-tags"
5253
)
5354

55+
var (
56+
errNoNodesAvailable = errors.New("no nodes available for nodebalancer")
57+
)
58+
5459
type lbNotFoundError struct {
5560
serviceNn string
5661
nodeBalancerID int
@@ -256,6 +261,10 @@ func (l *loadbalancers) EnsureLoadBalancer(ctx context.Context, clusterName stri
256261

257262
//nolint:funlen
258263
func (l *loadbalancers) updateNodeBalancer(ctx context.Context, service *v1.Service, nodes []*v1.Node, nb *linodego.NodeBalancer) (err error) {
264+
if len(nodes) == 0 {
265+
return fmt.Errorf("%w: service %s", errNoNodesAvailable, getServiceNn(service))
266+
}
267+
259268
connThrottle := getConnectionThrottle(service)
260269
if connThrottle != nb.ClientConnThrottle {
261270
update := nb.GetUpdateOptions()
@@ -607,6 +616,9 @@ func (l *loadbalancers) addTLSCert(ctx context.Context, service *v1.Service, nbC
607616
// buildLoadBalancerRequest returns a linodego.NodeBalancer
608617
// requests for service across nodes.
609618
func (l *loadbalancers) buildLoadBalancerRequest(ctx context.Context, clusterName string, service *v1.Service, nodes []*v1.Node) (*linodego.NodeBalancer, error) {
619+
if len(nodes) == 0 {
620+
return nil, fmt.Errorf("%w: cluster %s, service %s", errNoNodesAvailable, clusterName, getServiceNn(service))
621+
}
610622
ports := service.Spec.Ports
611623
configs := make([]*linodego.NodeBalancerConfigCreateOptions, 0, len(ports))
612624

cloud/linode/loadbalancers_test.go

Lines changed: 57 additions & 1 deletion
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"
@@ -180,6 +181,10 @@ func TestCCMLoadBalancers(t *testing.T) {
180181
name: "Cleanup does not call the API unless Service annotated",
181182
f: testCleanupDoesntCall,
182183
},
184+
{
185+
name: "Update Load Balancer - No Nodes",
186+
f: testUpdateLoadBalancerNoNodes,
187+
},
183188
}
184189

185190
for _, tc := range testCases {
@@ -229,7 +234,9 @@ func testCreateNodeBalancer(t *testing.T, client *linodego.Client, _ *fakeAPI) {
229234
}
230235

231236
lb := &loadbalancers{client, "us-west", nil}
232-
var nodes []*v1.Node
237+
nodes := []*v1.Node{
238+
{ObjectMeta: metav1.ObjectMeta{Name: "node-1"}},
239+
}
233240
nb, err := lb.buildLoadBalancerRequest(context.TODO(), "linodelb", svc, nodes)
234241
if err != nil {
235242
t.Fatal(err)
@@ -1631,6 +1638,55 @@ func testCleanupDoesntCall(t *testing.T, client *linodego.Client, fakeAPI *fakeA
16311638
})
16321639
}
16331640

1641+
func testUpdateLoadBalancerNoNodes(t *testing.T, client *linodego.Client, _ *fakeAPI) {
1642+
svc := &v1.Service{
1643+
ObjectMeta: metav1.ObjectMeta{
1644+
Name: randString(10),
1645+
UID: "foobar123",
1646+
Annotations: map[string]string{},
1647+
},
1648+
Spec: v1.ServiceSpec{
1649+
Ports: []v1.ServicePort{
1650+
{
1651+
Name: randString(10),
1652+
Protocol: "http",
1653+
Port: int32(80),
1654+
NodePort: int32(8080),
1655+
},
1656+
},
1657+
},
1658+
}
1659+
1660+
lb := &loadbalancers{client, "us-west", nil}
1661+
defer lb.EnsureLoadBalancerDeleted(context.TODO(), "linodelb", svc)
1662+
1663+
fakeClientset := fake.NewSimpleClientset()
1664+
lb.kubeClient = fakeClientset
1665+
1666+
nodeBalancer, err := client.CreateNodeBalancer(context.TODO(), linodego.NodeBalancerCreateOptions{
1667+
Region: lb.zone,
1668+
})
1669+
if err != nil {
1670+
t.Fatalf("failed to create NodeBalancer: %s", err)
1671+
}
1672+
svc.Status.LoadBalancer = *makeLoadBalancerStatus(svc, nodeBalancer)
1673+
stubService(fakeClientset, svc)
1674+
svc.ObjectMeta.SetAnnotations(map[string]string{
1675+
annLinodeNodeBalancerID: strconv.Itoa(nodeBalancer.ID),
1676+
})
1677+
1678+
// setup done, test ensure/update
1679+
nodes := []*v1.Node{}
1680+
1681+
if _, err = lb.EnsureLoadBalancer(context.TODO(), "linodelb", svc, nodes); !stderrors.Is(err, errNoNodesAvailable) {
1682+
t.Errorf("EnsureLoadBalancer should return %v, got %v", errNoNodesAvailable, err)
1683+
}
1684+
1685+
if err := lb.UpdateLoadBalancer(context.TODO(), "linodelb", svc, nodes); !stderrors.Is(err, errNoNodesAvailable) {
1686+
t.Errorf("UpdateLoadBalancer should return %v, got %v", errNoNodesAvailable, err)
1687+
}
1688+
}
1689+
16341690
func testGetNodeBalancerForServiceIDDoesNotExist(t *testing.T, client *linodego.Client, _ *fakeAPI) {
16351691
lb := &loadbalancers{client, "us-west", nil}
16361692
bogusNodeBalancerID := "123456"

0 commit comments

Comments
 (0)