Skip to content

Commit 5476125

Browse files
committed
Use builder methods to create NodeInfoComparator functions
1 parent ee627f2 commit 5476125

File tree

9 files changed

+67
-53
lines changed

9 files changed

+67
-53
lines changed

cluster-autoscaler/main.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -293,10 +293,10 @@ func buildAutoscaler() (core.Autoscaler, error) {
293293
processors.PodListProcessor = core.NewFilterOutSchedulablePodListProcessor()
294294
if autoscalingOptions.CloudProviderName == cloudprovider.AzureProviderName {
295295
processors.NodeGroupSetProcessor = &nodegroupset.BalancingNodeGroupSetProcessor{
296-
Comparator: nodegroupset.IsAzureNodeInfoSimilar}
296+
Comparator: nodegroupset.CreateAzureNodeInfoComparator()}
297297
} else if autoscalingOptions.CloudProviderName == cloudprovider.AwsProviderName {
298298
processors.NodeGroupSetProcessor = &nodegroupset.BalancingNodeGroupSetProcessor{
299-
Comparator: nodegroupset.IsAwsNodeInfoSimilar}
299+
Comparator: nodegroupset.CreateAwsNodeInfoComparator()}
300300
}
301301

302302
opts := core.AutoscalerOptions{

cluster-autoscaler/processors/nodegroupset/aws_nodegroups.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,7 @@ import (
2020
schedulernodeinfo "k8s.io/kubernetes/pkg/scheduler/nodeinfo"
2121
)
2222

23-
// IsAwsNodeInfoSimilar adds AWS specific node labels to the list of ignored labels.
24-
func IsAwsNodeInfoSimilar(n1, n2 *schedulernodeinfo.NodeInfo) bool {
23+
func CreateAwsNodeInfoComparator() NodeInfoComparator {
2524
awsIgnoredLabels := map[string]bool{
2625
"alpha.eksctl.io/instance-id": true, // this is a label used by eksctl to identify instances.
2726
"alpha.eksctl.io/nodegroup-name": true, // this is a label used by eksctl to identify "node group" names.
@@ -33,5 +32,8 @@ func IsAwsNodeInfoSimilar(n1, n2 *schedulernodeinfo.NodeInfo) bool {
3332
for k, v := range BasicIgnoredLabels {
3433
awsIgnoredLabels[k] = v
3534
}
36-
return IsCloudProviderNodeInfoSimilar(n1, n2, awsIgnoredLabels)
35+
36+
return func(n1, n2 *schedulernodeinfo.NodeInfo) bool {
37+
return IsCloudProviderNodeInfoSimilar(n1, n2, awsIgnoredLabels)
38+
}
3739
}

cluster-autoscaler/processors/nodegroupset/azure_nodegroups.go

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,17 +29,20 @@ func nodesFromSameAzureNodePool(n1, n2 *schedulernodeinfo.NodeInfo) bool {
2929
return n1AzureNodePool != "" && n1AzureNodePool == n2AzureNodePool
3030
}
3131

32-
// IsAzureNodeInfoSimilar compares if two nodes should be considered part of the
32+
// Returned NodeInfoComparator compares if two nodes should be considered part of the
3333
// same NodeGroupSet. This is true if they either belong to the same Azure agentpool
34-
// or match usual conditions checked by IsAzureNodeInfoSimilar, even if they have different agentpool labels.
35-
func IsAzureNodeInfoSimilar(n1, n2 *schedulernodeinfo.NodeInfo) bool {
36-
if nodesFromSameAzureNodePool(n1, n2) {
37-
return true
38-
}
34+
// or match usual conditions checked by IsCloudProviderNodeInfoSimilar, even if they have different agentpool labels.
35+
func CreateAzureNodeInfoComparator() NodeInfoComparator {
3936
azureIgnoredLabels := make(map[string]bool)
4037
for k, v := range BasicIgnoredLabels {
4138
azureIgnoredLabels[k] = v
4239
}
4340
azureIgnoredLabels[AzureNodepoolLabel] = true
44-
return IsCloudProviderNodeInfoSimilar(n1, n2, azureIgnoredLabels)
41+
42+
return func(n1, n2 *schedulernodeinfo.NodeInfo) bool {
43+
if nodesFromSameAzureNodePool(n1, n2) {
44+
return true
45+
}
46+
return IsCloudProviderNodeInfoSimilar(n1, n2, azureIgnoredLabels)
47+
}
4548
}

cluster-autoscaler/processors/nodegroupset/azure_nodegroups_test.go

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,47 +29,48 @@ import (
2929
)
3030

3131
func TestIsAzureNodeInfoSimilar(t *testing.T) {
32+
comparator := CreateAzureNodeInfoComparator()
3233
n1 := BuildTestNode("node1", 1000, 2000)
3334
n1.ObjectMeta.Labels["test-label"] = "test-value"
3435
n1.ObjectMeta.Labels["character"] = "thing"
3536
n2 := BuildTestNode("node2", 1000, 2000)
3637
n2.ObjectMeta.Labels["test-label"] = "test-value"
3738
// No node-pool labels.
38-
checkNodesSimilar(t, n1, n2, IsAzureNodeInfoSimilar, false)
39+
checkNodesSimilar(t, n1, n2, comparator, false)
3940
// Empty agentpool labels
4041
n1.ObjectMeta.Labels["agentpool"] = ""
4142
n2.ObjectMeta.Labels["agentpool"] = ""
42-
checkNodesSimilar(t, n1, n2, IsAzureNodeInfoSimilar, false)
43+
checkNodesSimilar(t, n1, n2, comparator, false)
4344
// Only one non empty
4445
n1.ObjectMeta.Labels["agentpool"] = ""
4546
n2.ObjectMeta.Labels["agentpool"] = "foo"
46-
checkNodesSimilar(t, n1, n2, IsAzureNodeInfoSimilar, false)
47+
checkNodesSimilar(t, n1, n2, comparator, false)
4748
// Only one present
4849
delete(n1.ObjectMeta.Labels, "agentpool")
4950
n2.ObjectMeta.Labels["agentpool"] = "foo"
50-
checkNodesSimilar(t, n1, n2, IsAzureNodeInfoSimilar, false)
51+
checkNodesSimilar(t, n1, n2, comparator, false)
5152
// Different vales
5253
n1.ObjectMeta.Labels["agentpool"] = "foo1"
5354
n2.ObjectMeta.Labels["agentpool"] = "foo2"
54-
checkNodesSimilar(t, n1, n2, IsAzureNodeInfoSimilar, false)
55+
checkNodesSimilar(t, n1, n2, comparator, false)
5556
// Same values
5657
n1.ObjectMeta.Labels["agentpool"] = "foo"
5758
n2.ObjectMeta.Labels["agentpool"] = "foo"
58-
checkNodesSimilar(t, n1, n2, IsAzureNodeInfoSimilar, true)
59+
checkNodesSimilar(t, n1, n2, comparator, true)
5960
// Same labels except for agentpool
6061
delete(n1.ObjectMeta.Labels, "character")
6162
n1.ObjectMeta.Labels["agentpool"] = "foo"
6263
n2.ObjectMeta.Labels["agentpool"] = "bar"
63-
checkNodesSimilar(t, n1, n2, IsAzureNodeInfoSimilar, true)
64+
checkNodesSimilar(t, n1, n2, comparator, true)
6465
}
6566

6667
func TestFindSimilarNodeGroupsAzureBasic(t *testing.T) {
67-
processor := &BalancingNodeGroupSetProcessor{Comparator: IsAzureNodeInfoSimilar}
68+
processor := &BalancingNodeGroupSetProcessor{Comparator: CreateAzureNodeInfoComparator()}
6869
basicSimilarNodeGroupsTest(t, processor)
6970
}
7071

7172
func TestFindSimilarNodeGroupsAzureByLabel(t *testing.T) {
72-
processor := &BalancingNodeGroupSetProcessor{Comparator: IsAzureNodeInfoSimilar}
73+
processor := &BalancingNodeGroupSetProcessor{Comparator: CreateAzureNodeInfoComparator()}
7374
context := &context.AutoscalingContext{}
7475

7576
n1 := BuildTestNode("n1", 1000, 1000)

cluster-autoscaler/processors/nodegroupset/balancing_processor.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ type BalancingNodeGroupSetProcessor struct {
3232
Comparator NodeInfoComparator
3333
}
3434

35-
// FindSimilarNodeGroups returns a list of NodeGroups similar to the given one.
36-
// Two groups are similar if the NodeInfos for them compare equal using IsNodeInfoSimilar.
35+
// FindSimilarNodeGroups returns a list of NodeGroups similar to the given one using the
36+
// BalancingNodeGroupSetProcessor's comparator function.
3737
func (b *BalancingNodeGroupSetProcessor) FindSimilarNodeGroups(context *context.AutoscalingContext, nodeGroup cloudprovider.NodeGroup,
3838
nodeInfosForGroups map[string]*schedulernodeinfo.NodeInfo) ([]cloudprovider.NodeGroup, errors.AutoscalerError) {
3939

@@ -58,7 +58,7 @@ func (b *BalancingNodeGroupSetProcessor) FindSimilarNodeGroups(context *context.
5858
}
5959
comparator := b.Comparator
6060
if comparator == nil {
61-
comparator = IsNodeInfoSimilar
61+
panic("BalancingNodeGroupSetProcessor comparator not set")
6262
}
6363
if comparator(nodeInfo, ngNodeInfo) {
6464
result = append(result, ng)

cluster-autoscaler/processors/nodegroupset/balancing_processor_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,12 @@ func basicSimilarNodeGroupsTest(t *testing.T, processor NodeGroupSetProcessor) {
7272
}
7373

7474
func TestFindSimilarNodeGroups(t *testing.T) {
75-
processor := &BalancingNodeGroupSetProcessor{}
75+
processor := NewDefaultNodeGroupSetProcessor()
7676
basicSimilarNodeGroupsTest(t, processor)
7777
}
7878

7979
func TestBalanceSingleGroup(t *testing.T) {
80-
processor := &BalancingNodeGroupSetProcessor{}
80+
processor := NewDefaultNodeGroupSetProcessor()
8181
context := &context.AutoscalingContext{}
8282

8383
provider := testprovider.NewTestCloudProvider(nil, nil)
@@ -97,7 +97,7 @@ func TestBalanceSingleGroup(t *testing.T) {
9797
}
9898

9999
func TestBalanceUnderMaxSize(t *testing.T) {
100-
processor := &BalancingNodeGroupSetProcessor{}
100+
processor := NewDefaultNodeGroupSetProcessor()
101101
context := &context.AutoscalingContext{}
102102

103103
provider := testprovider.NewTestCloudProvider(nil, nil)
@@ -147,7 +147,7 @@ func TestBalanceUnderMaxSize(t *testing.T) {
147147
}
148148

149149
func TestBalanceHittingMaxSize(t *testing.T) {
150-
processor := &BalancingNodeGroupSetProcessor{}
150+
processor := NewDefaultNodeGroupSetProcessor()
151151
context := &context.AutoscalingContext{}
152152

153153
provider := testprovider.NewTestCloudProvider(nil, nil)

cluster-autoscaler/processors/nodegroupset/compare_nodegroups.go

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -85,18 +85,19 @@ func compareLabels(nodes []*schedulernodeinfo.NodeInfo, ignoredLabels map[string
8585
}
8686
return true
8787
}
88+
// CreateGenericNodeInfoComparator returns a generic comparator that checks for node group similarity
89+
// based on a standard set of widely-applicable ignore labels
90+
func CreateGenericNodeInfoComparator() NodeInfoComparator {
91+
return func(n1, n2 *schedulernodeinfo.NodeInfo) bool {
92+
return IsCloudProviderNodeInfoSimilar(n1, n2, BasicIgnoredLabels)
93+
}
94+
}
8895

89-
// IsNodeInfoSimilar returns true if two NodeInfos are similar enough to consider
96+
// IsCloudProviderNodeInfoSimilar returns true if two NodeInfos are similar enough to consider
9097
// that the NodeGroups they come from are part of the same NodeGroupSet. The criteria are
9198
// somewhat arbitrary, but generally we check if resources provided by both nodes
9299
// are similar enough to likely be the same type of machine and if the set of labels
93-
// is the same (except for a pre-defined set of labels like hostname or zone).
94-
func IsNodeInfoSimilar(n1, n2 *schedulernodeinfo.NodeInfo) bool {
95-
return IsCloudProviderNodeInfoSimilar(n1, n2, BasicIgnoredLabels)
96-
}
97-
98-
// IsCloudProviderNodeInfoSimilar remains the same logic of IsNodeInfoSimilar with the
99-
// customized set of labels that should be ignored when comparing the similarity of two NodeInfos.
100+
// is the same (except for a set of labels passed in to be ignored like hostname or zone).
100101
func IsCloudProviderNodeInfoSimilar(n1, n2 *schedulernodeinfo.NodeInfo, ignoredLabels map[string]bool) bool {
101102
capacity := make(map[apiv1.ResourceName][]resource.Quantity)
102103
allocatable := make(map[apiv1.ResourceName][]resource.Quantity)

cluster-autoscaler/processors/nodegroupset/compare_nodegroups_test.go

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -41,37 +41,40 @@ func checkNodesSimilarWithPods(t *testing.T, n1, n2 *apiv1.Node, pods1, pods2 []
4141
}
4242

4343
func TestIdenticalNodesSimilar(t *testing.T) {
44+
comparator := CreateGenericNodeInfoComparator()
4445
n1 := BuildTestNode("node1", 1000, 2000)
4546
n2 := BuildTestNode("node2", 1000, 2000)
46-
checkNodesSimilar(t, n1, n2, IsNodeInfoSimilar, true)
47+
checkNodesSimilar(t, n1, n2, comparator, true)
4748
}
4849

4950
func TestNodesSimilarVariousRequirements(t *testing.T) {
51+
comparator := CreateGenericNodeInfoComparator()
5052
n1 := BuildTestNode("node1", 1000, 2000)
5153

5254
// Different CPU capacity
5355
n2 := BuildTestNode("node2", 1000, 2000)
5456
n2.Status.Capacity[apiv1.ResourceCPU] = *resource.NewMilliQuantity(1001, resource.DecimalSI)
55-
checkNodesSimilar(t, n1, n2, IsNodeInfoSimilar, false)
57+
checkNodesSimilar(t, n1, n2, comparator, false)
5658

5759
// Same CPU capacity, but slightly different allocatable
5860
n3 := BuildTestNode("node3", 1000, 2000)
5961
n3.Status.Allocatable[apiv1.ResourceCPU] = *resource.NewMilliQuantity(999, resource.DecimalSI)
60-
checkNodesSimilar(t, n1, n3, IsNodeInfoSimilar, true)
62+
checkNodesSimilar(t, n1, n3, comparator, true)
6163

6264
// Same CPU capacity, significantly different allocatable
6365
n4 := BuildTestNode("node4", 1000, 2000)
6466
n4.Status.Allocatable[apiv1.ResourceCPU] = *resource.NewMilliQuantity(500, resource.DecimalSI)
65-
checkNodesSimilar(t, n1, n4, IsNodeInfoSimilar, false)
67+
checkNodesSimilar(t, n1, n4, comparator, false)
6668

6769
// One with GPU, one without
6870
n5 := BuildTestNode("node5", 1000, 2000)
6971
n5.Status.Capacity[gpu.ResourceNvidiaGPU] = *resource.NewQuantity(1, resource.DecimalSI)
7072
n5.Status.Allocatable[gpu.ResourceNvidiaGPU] = n5.Status.Capacity[gpu.ResourceNvidiaGPU]
71-
checkNodesSimilar(t, n1, n5, IsNodeInfoSimilar, false)
73+
checkNodesSimilar(t, n1, n5, comparator, false)
7274
}
7375

7476
func TestNodesSimilarVariousRequirementsAndPods(t *testing.T) {
77+
comparator := CreateGenericNodeInfoComparator()
7578
n1 := BuildTestNode("node1", 1000, 2000)
7679
p1 := BuildTestPod("pod1", 500, 1000)
7780
p1.Spec.NodeName = "node1"
@@ -80,37 +83,39 @@ func TestNodesSimilarVariousRequirementsAndPods(t *testing.T) {
8083
n2 := BuildTestNode("node2", 1000, 2000)
8184
n2.Status.Allocatable[apiv1.ResourceCPU] = *resource.NewMilliQuantity(500, resource.DecimalSI)
8285
n2.Status.Allocatable[apiv1.ResourceMemory] = *resource.NewQuantity(1000, resource.DecimalSI)
83-
checkNodesSimilarWithPods(t, n1, n2, []*apiv1.Pod{p1}, []*apiv1.Pod{}, IsNodeInfoSimilar, false)
86+
checkNodesSimilarWithPods(t, n1, n2, []*apiv1.Pod{p1}, []*apiv1.Pod{}, comparator, false)
8487

8588
// Same requests of pods
8689
n3 := BuildTestNode("node3", 1000, 2000)
8790
p3 := BuildTestPod("pod3", 500, 1000)
8891
p3.Spec.NodeName = "node3"
89-
checkNodesSimilarWithPods(t, n1, n3, []*apiv1.Pod{p1}, []*apiv1.Pod{p3}, IsNodeInfoSimilar, true)
92+
checkNodesSimilarWithPods(t, n1, n3, []*apiv1.Pod{p1}, []*apiv1.Pod{p3}, comparator, true)
9093

9194
// Similar allocatable, similar pods
9295
n4 := BuildTestNode("node4", 1000, 2000)
9396
n4.Status.Allocatable[apiv1.ResourceCPU] = *resource.NewMilliQuantity(999, resource.DecimalSI)
9497
p4 := BuildTestPod("pod4", 501, 1001)
9598
p4.Spec.NodeName = "node4"
96-
checkNodesSimilarWithPods(t, n1, n4, []*apiv1.Pod{p1}, []*apiv1.Pod{p4}, IsNodeInfoSimilar, true)
99+
checkNodesSimilarWithPods(t, n1, n4, []*apiv1.Pod{p1}, []*apiv1.Pod{p4}, comparator, true)
97100
}
98101

99102
func TestNodesSimilarVariousMemoryRequirements(t *testing.T) {
103+
comparator := CreateGenericNodeInfoComparator()
100104
n1 := BuildTestNode("node1", 1000, MaxMemoryDifferenceInKiloBytes)
101105

102106
// Different memory capacity within tolerance
103107
n2 := BuildTestNode("node2", 1000, MaxMemoryDifferenceInKiloBytes)
104108
n2.Status.Capacity[apiv1.ResourceMemory] = *resource.NewQuantity(2*MaxMemoryDifferenceInKiloBytes, resource.DecimalSI)
105-
checkNodesSimilar(t, n1, n2, IsNodeInfoSimilar, true)
109+
checkNodesSimilar(t, n1, n2, comparator, true)
106110

107111
// Different memory capacity exceeds tolerance
108112
n3 := BuildTestNode("node3", 1000, MaxMemoryDifferenceInKiloBytes)
109113
n3.Status.Capacity[apiv1.ResourceMemory] = *resource.NewQuantity(2*MaxMemoryDifferenceInKiloBytes+1, resource.DecimalSI)
110-
checkNodesSimilar(t, n1, n3, IsNodeInfoSimilar, false)
114+
checkNodesSimilar(t, n1, n3, comparator, false)
111115
}
112116

113117
func TestNodesSimilarVariousLabels(t *testing.T) {
118+
comparator := CreateGenericNodeInfoComparator()
114119
n1 := BuildTestNode("node1", 1000, 2000)
115120
n1.ObjectMeta.Labels["test-label"] = "test-value"
116121
n1.ObjectMeta.Labels["character"] = "winnie the pooh"
@@ -119,27 +124,27 @@ func TestNodesSimilarVariousLabels(t *testing.T) {
119124
n2.ObjectMeta.Labels["test-label"] = "test-value"
120125

121126
// Missing character label
122-
checkNodesSimilar(t, n1, n2, IsNodeInfoSimilar, false)
127+
checkNodesSimilar(t, n1, n2, comparator, false)
123128

124129
n2.ObjectMeta.Labels["character"] = "winnie the pooh"
125-
checkNodesSimilar(t, n1, n2, IsNodeInfoSimilar, true)
130+
checkNodesSimilar(t, n1, n2, comparator, true)
126131

127132
// Different hostname labels shouldn't matter
128133
n1.ObjectMeta.Labels[apiv1.LabelHostname] = "node1"
129134
n2.ObjectMeta.Labels[apiv1.LabelHostname] = "node2"
130-
checkNodesSimilar(t, n1, n2, IsNodeInfoSimilar, true)
135+
checkNodesSimilar(t, n1, n2, comparator, true)
131136

132137
// Different zone shouldn't matter either
133138
n1.ObjectMeta.Labels[apiv1.LabelZoneFailureDomain] = "mars-olympus-mons1-b"
134139
n2.ObjectMeta.Labels[apiv1.LabelZoneFailureDomain] = "us-houston1-a"
135-
checkNodesSimilar(t, n1, n2, IsNodeInfoSimilar, true)
140+
checkNodesSimilar(t, n1, n2, comparator, true)
136141

137142
// Different beta.kubernetes.io/fluentd-ds-ready should not matter
138143
n1.ObjectMeta.Labels["beta.kubernetes.io/fluentd-ds-ready"] = "true"
139144
n2.ObjectMeta.Labels["beta.kubernetes.io/fluentd-ds-ready"] = "false"
140-
checkNodesSimilar(t, n1, n2, IsNodeInfoSimilar, true)
145+
checkNodesSimilar(t, n1, n2, comparator, true)
141146

142147
n1.ObjectMeta.Labels["beta.kubernetes.io/fluentd-ds-ready"] = "true"
143148
delete(n2.ObjectMeta.Labels, "beta.kubernetes.io/fluentd-ds-ready")
144-
checkNodesSimilar(t, n1, n2, IsNodeInfoSimilar, true)
149+
checkNodesSimilar(t, n1, n2, comparator, true)
145150
}

cluster-autoscaler/processors/nodegroupset/nodegroup_set_processor.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,5 +71,7 @@ func (n *NoOpNodeGroupSetProcessor) CleanUp() {}
7171

7272
// NewDefaultNodeGroupSetProcessor creates an instance of NodeGroupSetProcessor.
7373
func NewDefaultNodeGroupSetProcessor() NodeGroupSetProcessor {
74-
return &BalancingNodeGroupSetProcessor{}
74+
return &BalancingNodeGroupSetProcessor{
75+
Comparator: CreateGenericNodeInfoComparator(),
76+
}
7577
}

0 commit comments

Comments
 (0)