Skip to content

Commit 80a8a8d

Browse files
committed
service controller: only sync LB node pools when relevant fields change
Signed-off-by: Andrew Sy Kim <[email protected]>
1 parent 5983660 commit 80a8a8d

File tree

2 files changed

+157
-0
lines changed

2 files changed

+157
-0
lines changed

pkg/controller/service/controller.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,20 @@ func New(
176176
s.nodeSyncLoop()
177177
},
178178
UpdateFunc: func(old, cur interface{}) {
179+
oldNode, ok := old.(*v1.Node)
180+
if !ok {
181+
return
182+
}
183+
184+
curNode, ok := cur.(*v1.Node)
185+
if !ok {
186+
return
187+
}
188+
189+
if !shouldSyncNode(oldNode, curNode) {
190+
return
191+
}
192+
179193
s.nodeSyncLoop()
180194
},
181195
DeleteFunc: func(old interface{}) {
@@ -649,6 +663,30 @@ func getNodeConditionPredicate() NodeConditionPredicate {
649663
}
650664
}
651665

666+
func shouldSyncNode(oldNode, newNode *v1.Node) bool {
667+
if oldNode.Spec.Unschedulable != newNode.Spec.Unschedulable {
668+
return true
669+
}
670+
671+
if !reflect.DeepEqual(oldNode.Labels, newNode.Labels) {
672+
return true
673+
}
674+
675+
return nodeReadyConditionStatus(oldNode) != nodeReadyConditionStatus(newNode)
676+
}
677+
678+
func nodeReadyConditionStatus(node *v1.Node) v1.ConditionStatus {
679+
for _, condition := range node.Status.Conditions {
680+
if condition.Type != v1.NodeReady {
681+
continue
682+
}
683+
684+
return condition.Status
685+
}
686+
687+
return ""
688+
}
689+
652690
// nodeSyncLoop handles updating the hosts pointed to by all load
653691
// balancers whenever the set of nodes in the cluster changes.
654692
func (s *Controller) nodeSyncLoop() {

pkg/controller/service/controller_test.go

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1486,3 +1486,122 @@ func TestListWithPredicate(t *testing.T) {
14861486
})
14871487
}
14881488
}
1489+
1490+
func Test_shouldSyncNode(t *testing.T) {
1491+
testcases := []struct {
1492+
name string
1493+
oldNode *v1.Node
1494+
newNode *v1.Node
1495+
shouldSync bool
1496+
}{
1497+
{
1498+
name: "spec.unschedable field changed",
1499+
oldNode: &v1.Node{
1500+
ObjectMeta: metav1.ObjectMeta{
1501+
Name: "node",
1502+
},
1503+
Spec: v1.NodeSpec{
1504+
Unschedulable: false,
1505+
},
1506+
},
1507+
newNode: &v1.Node{
1508+
ObjectMeta: metav1.ObjectMeta{
1509+
Name: "node",
1510+
},
1511+
Spec: v1.NodeSpec{
1512+
Unschedulable: true,
1513+
},
1514+
},
1515+
shouldSync: true,
1516+
},
1517+
{
1518+
name: "labels changed",
1519+
oldNode: &v1.Node{
1520+
ObjectMeta: metav1.ObjectMeta{
1521+
Name: "node",
1522+
Labels: map[string]string{},
1523+
},
1524+
},
1525+
newNode: &v1.Node{
1526+
ObjectMeta: metav1.ObjectMeta{
1527+
Name: "node",
1528+
Labels: map[string]string{
1529+
labelNodeRoleExcludeBalancer: "",
1530+
},
1531+
},
1532+
},
1533+
shouldSync: true,
1534+
},
1535+
{
1536+
name: "ready condition changed",
1537+
oldNode: &v1.Node{
1538+
ObjectMeta: metav1.ObjectMeta{
1539+
Name: "node",
1540+
},
1541+
Status: v1.NodeStatus{
1542+
Conditions: []v1.NodeCondition{
1543+
{
1544+
Type: v1.NodeReady,
1545+
Status: v1.ConditionTrue,
1546+
},
1547+
},
1548+
},
1549+
},
1550+
newNode: &v1.Node{
1551+
ObjectMeta: metav1.ObjectMeta{
1552+
Name: "node",
1553+
},
1554+
Status: v1.NodeStatus{
1555+
Conditions: []v1.NodeCondition{
1556+
{
1557+
Type: v1.NodeReady,
1558+
Status: v1.ConditionFalse,
1559+
},
1560+
},
1561+
},
1562+
},
1563+
shouldSync: true,
1564+
},
1565+
{
1566+
name: "not relevant condition changed and no ready condition",
1567+
oldNode: &v1.Node{
1568+
ObjectMeta: metav1.ObjectMeta{
1569+
Name: "node",
1570+
},
1571+
Status: v1.NodeStatus{
1572+
Conditions: []v1.NodeCondition{
1573+
{
1574+
Type: v1.NodeNetworkUnavailable,
1575+
Status: v1.ConditionTrue,
1576+
},
1577+
},
1578+
},
1579+
},
1580+
newNode: &v1.Node{
1581+
ObjectMeta: metav1.ObjectMeta{
1582+
Name: "node",
1583+
},
1584+
Status: v1.NodeStatus{
1585+
Conditions: []v1.NodeCondition{
1586+
{
1587+
Type: v1.NodeNetworkUnavailable,
1588+
Status: v1.ConditionFalse,
1589+
},
1590+
},
1591+
},
1592+
},
1593+
shouldSync: false,
1594+
},
1595+
}
1596+
1597+
for _, testcase := range testcases {
1598+
t.Run(testcase.name, func(t *testing.T) {
1599+
shouldSync := shouldSyncNode(testcase.oldNode, testcase.newNode)
1600+
if shouldSync != testcase.shouldSync {
1601+
t.Logf("actual shouldSyncNode: %v", shouldSync)
1602+
t.Logf("expected shouldSyncNode: %v", testcase.shouldSync)
1603+
t.Errorf("unexpected result from shouldSyncNode")
1604+
}
1605+
})
1606+
}
1607+
}

0 commit comments

Comments
 (0)