Skip to content

Commit 7386a22

Browse files
Modify scale down set processor to add reasons to unremovable nodes
1 parent 00e19fd commit 7386a22

File tree

16 files changed

+506
-140
lines changed

16 files changed

+506
-140
lines changed

cluster-autoscaler/core/scaledown/planner/planner.go

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ package planner
1818

1919
import (
2020
"fmt"
21-
"math"
2221
"time"
2322

2423
apiv1 "k8s.io/api/core/v1"
@@ -73,10 +72,10 @@ type Planner struct {
7372
minUpdateInterval time.Duration
7473
eligibilityChecker eligibilityChecker
7574
nodeUtilizationMap map[string]utilization.Info
76-
actuationStatus scaledown.ActuationStatus
7775
resourceLimitsFinder *resource.LimitsFinder
7876
cc controllerReplicasCalculator
7977
scaleDownSetProcessor nodes.ScaleDownSetProcessor
78+
scaleDownContext *nodes.ScaleDownContext
8079
}
8180

8281
// New creates a new Planner object.
@@ -97,6 +96,7 @@ func New(context *context.AutoscalingContext, processors *processors.Autoscaling
9796
resourceLimitsFinder: resourceLimitsFinder,
9897
cc: newControllerReplicasCalculator(context.ListerRegistry),
9998
scaleDownSetProcessor: processors.ScaleDownSetProcessor,
99+
scaleDownContext: nodes.NewDefaultScaleDownContext(),
100100
minUpdateInterval: minUpdateInterval,
101101
}
102102
}
@@ -110,7 +110,7 @@ func (p *Planner) UpdateClusterState(podDestinations, scaleDownCandidates []*api
110110
p.minUpdateInterval = updateInterval
111111
}
112112
p.latestUpdate = currentTime
113-
p.actuationStatus = as
113+
p.scaleDownContext.ActuationStatus = as
114114
// Avoid persisting changes done by the simulation.
115115
p.context.ClusterSnapshot.Fork()
116116
defer p.context.ClusterSnapshot.Revert()
@@ -147,22 +147,17 @@ func (p *Planner) NodesToDelete(_ time.Time) (empty, needDrain []*apiv1.Node) {
147147
klog.Errorf("Nothing will scale down, failed to create resource limiter: %v", err)
148148
return nil, nil
149149
}
150-
limitsLeft := p.resourceLimitsFinder.LimitsLeft(p.context, nodes, resourceLimiter, p.latestUpdate)
151-
emptyRemovable, needDrainRemovable, unremovable := p.unneededNodes.RemovableAt(p.context, p.latestUpdate, limitsLeft, resourceLimiter.GetResources(), p.actuationStatus)
152-
for _, u := range unremovable {
153-
p.unremovableNodes.Add(u)
154-
}
155-
needDrainRemovable = sortByRisk(needDrainRemovable)
156-
nodesToRemove := p.scaleDownSetProcessor.GetNodesToRemove(
157-
p.context,
158-
// We need to pass empty nodes first, as there might be some non-empty scale
159-
// downs already in progress. If we pass the empty nodes first, they will be first
160-
// to get deleted, thus we decrease chances of hitting the limit on non-empty scale down.
161-
append(emptyRemovable, needDrainRemovable...),
162-
// No need to limit the number of nodes, since it will happen later, in the actuation stage.
163-
// It will make a more appropriate decision by using additional information about deletions
164-
// in progress.
165-
math.MaxInt)
150+
p.scaleDownContext.ResourcesLeft = p.resourceLimitsFinder.LimitsLeft(p.context, nodes, resourceLimiter, p.latestUpdate).DeepCopy()
151+
p.scaleDownContext.ResourcesWithLimits = resourceLimiter.GetResources()
152+
emptyRemovableNodes, needDrainRemovableNodes, unremovableNodes := p.unneededNodes.RemovableAt(p.context, *p.scaleDownContext, p.latestUpdate)
153+
p.addUnremovableNodes(unremovableNodes)
154+
155+
needDrainRemovableNodes = sortByRisk(needDrainRemovableNodes)
156+
candidatesToBeRemoved := append(emptyRemovableNodes, needDrainRemovableNodes...)
157+
158+
nodesToRemove, unremovableNodes := p.scaleDownSetProcessor.FilterUnremovableNodes(p.context, p.scaleDownContext, candidatesToBeRemoved)
159+
p.addUnremovableNodes(unremovableNodes)
160+
166161
for _, nodeToRemove := range nodesToRemove {
167162
if len(nodeToRemove.PodsToReschedule) > 0 {
168163
needDrain = append(needDrain, nodeToRemove.Node)
@@ -174,6 +169,12 @@ func (p *Planner) NodesToDelete(_ time.Time) (empty, needDrain []*apiv1.Node) {
174169
return empty, needDrain
175170
}
176171

172+
func (p *Planner) addUnremovableNodes(unremovableNodes []simulator.UnremovableNode) {
173+
for _, u := range unremovableNodes {
174+
p.unremovableNodes.Add(&u)
175+
}
176+
}
177+
177178
func allNodes(s clustersnapshot.ClusterSnapshot) ([]*apiv1.Node, error) {
178179
nodeInfos, err := s.NodeInfos().List()
179180
if err != nil {
@@ -212,7 +213,7 @@ func (p *Planner) NodeUtilizationMap() map[string]utilization.Info {
212213
// For pods that are controlled by controller known by CA, it will check whether
213214
// they have been recreated and will inject only not yet recreated pods.
214215
func (p *Planner) injectRecentlyEvictedPods() error {
215-
recentlyEvictedRecreatablePods := pod_util.FilterRecreatablePods(p.actuationStatus.RecentEvictions())
216+
recentlyEvictedRecreatablePods := pod_util.FilterRecreatablePods(p.scaleDownContext.ActuationStatus.RecentEvictions())
216217
return p.injectPods(filterOutRecreatedPods(recentlyEvictedRecreatablePods, p.cc))
217218
}
218219

cluster-autoscaler/core/scaledown/planner/planner_test.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import (
3535
"k8s.io/autoscaler/cluster-autoscaler/core/scaledown/status"
3636
"k8s.io/autoscaler/cluster-autoscaler/core/scaledown/unremovable"
3737
. "k8s.io/autoscaler/cluster-autoscaler/core/test"
38+
processorstest "k8s.io/autoscaler/cluster-autoscaler/processors/test"
3839
"k8s.io/autoscaler/cluster-autoscaler/simulator"
3940
"k8s.io/autoscaler/cluster-autoscaler/simulator/clustersnapshot"
4041
"k8s.io/autoscaler/cluster-autoscaler/simulator/options"
@@ -501,7 +502,7 @@ func TestUpdateClusterState(t *testing.T) {
501502
assert.NoError(t, err)
502503
clustersnapshot.InitializeClusterSnapshotOrDie(t, context.ClusterSnapshot, tc.nodes, tc.pods)
503504
deleteOptions := options.NodeDeleteOptions{}
504-
p := New(&context, NewTestProcessors(&context), deleteOptions, nil)
505+
p := New(&context, processorstest.NewTestProcessors(&context), deleteOptions, nil)
505506
p.eligibilityChecker = &fakeEligibilityChecker{eligible: asMap(tc.eligible)}
506507
if tc.isSimulationTimeout {
507508
context.AutoscalingOptions.ScaleDownSimulationTimeout = 1 * time.Second
@@ -697,7 +698,7 @@ func TestUpdateClusterStatUnneededNodesLimit(t *testing.T) {
697698
assert.NoError(t, err)
698699
clustersnapshot.InitializeClusterSnapshotOrDie(t, context.ClusterSnapshot, nodes, nil)
699700
deleteOptions := options.NodeDeleteOptions{}
700-
p := New(&context, NewTestProcessors(&context), deleteOptions, nil)
701+
p := New(&context, processorstest.NewTestProcessors(&context), deleteOptions, nil)
701702
p.eligibilityChecker = &fakeEligibilityChecker{eligible: asMap(nodeNames(nodes))}
702703
p.minUpdateInterval = tc.updateInterval
703704
p.unneededNodes.Update(previouslyUnneeded, time.Now())
@@ -865,9 +866,9 @@ func TestNodesToDelete(t *testing.T) {
865866
assert.NoError(t, err)
866867
clustersnapshot.InitializeClusterSnapshotOrDie(t, context.ClusterSnapshot, allNodes, nil)
867868
deleteOptions := options.NodeDeleteOptions{}
868-
p := New(&context, NewTestProcessors(&context), deleteOptions, nil)
869+
p := New(&context, processorstest.NewTestProcessors(&context), deleteOptions, nil)
869870
p.latestUpdate = time.Now()
870-
p.actuationStatus = deletiontracker.NewNodeDeletionTracker(0 * time.Second)
871+
p.scaleDownContext.ActuationStatus = deletiontracker.NewNodeDeletionTracker(0 * time.Second)
871872
p.unneededNodes.Update(allRemovables, time.Now().Add(-1*time.Hour))
872873
p.eligibilityChecker = &fakeEligibilityChecker{eligible: asMap(nodeNames(allNodes))}
873874
empty, drain := p.NodesToDelete(time.Now())

cluster-autoscaler/core/scaledown/unneeded/nodes.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"k8s.io/autoscaler/cluster-autoscaler/core/scaledown/eligibility"
2727
"k8s.io/autoscaler/cluster-autoscaler/core/scaledown/resource"
2828
"k8s.io/autoscaler/cluster-autoscaler/metrics"
29+
"k8s.io/autoscaler/cluster-autoscaler/processors/nodes"
2930
"k8s.io/autoscaler/cluster-autoscaler/simulator"
3031
"k8s.io/autoscaler/cluster-autoscaler/utils"
3132
kube_util "k8s.io/autoscaler/cluster-autoscaler/utils/kubernetes"
@@ -117,31 +118,30 @@ func (n *Nodes) Drop(node string) {
117118
// RemovableAt returns all nodes that can be removed at a given time, divided
118119
// into empty and non-empty node lists, as well as a list of nodes that were
119120
// unneeded, but are not removable, annotated by reason.
120-
func (n *Nodes) RemovableAt(context *context.AutoscalingContext, ts time.Time, resourcesLeft resource.Limits, resourcesWithLimits []string, as scaledown.ActuationStatus) (empty, needDrain []simulator.NodeToBeRemoved, unremovable []*simulator.UnremovableNode) {
121+
func (n *Nodes) RemovableAt(context *context.AutoscalingContext, scaleDownContext nodes.ScaleDownContext, ts time.Time) (empty, needDrain []simulator.NodeToBeRemoved, unremovable []simulator.UnremovableNode) {
121122
nodeGroupSize := utils.GetNodeGroupSizeMap(context.CloudProvider)
122-
resourcesLeftCopy := resourcesLeft.DeepCopy()
123123
emptyNodes, drainNodes := n.splitEmptyAndNonEmptyNodes()
124124

125125
for nodeName, v := range emptyNodes {
126126
klog.V(2).Infof("%s was unneeded for %s", nodeName, ts.Sub(v.since).String())
127-
if r := n.unremovableReason(context, v, ts, nodeGroupSize, resourcesLeftCopy, resourcesWithLimits, as); r != simulator.NoReason {
128-
unremovable = append(unremovable, &simulator.UnremovableNode{Node: v.ntbr.Node, Reason: r})
127+
if r := n.unremovableReason(context, scaleDownContext, v, ts, nodeGroupSize); r != simulator.NoReason {
128+
unremovable = append(unremovable, simulator.UnremovableNode{Node: v.ntbr.Node, Reason: r})
129129
continue
130130
}
131131
empty = append(empty, v.ntbr)
132132
}
133133
for nodeName, v := range drainNodes {
134134
klog.V(2).Infof("%s was unneeded for %s", nodeName, ts.Sub(v.since).String())
135-
if r := n.unremovableReason(context, v, ts, nodeGroupSize, resourcesLeftCopy, resourcesWithLimits, as); r != simulator.NoReason {
136-
unremovable = append(unremovable, &simulator.UnremovableNode{Node: v.ntbr.Node, Reason: r})
135+
if r := n.unremovableReason(context, scaleDownContext, v, ts, nodeGroupSize); r != simulator.NoReason {
136+
unremovable = append(unremovable, simulator.UnremovableNode{Node: v.ntbr.Node, Reason: r})
137137
continue
138138
}
139139
needDrain = append(needDrain, v.ntbr)
140140
}
141141
return
142142
}
143143

144-
func (n *Nodes) unremovableReason(context *context.AutoscalingContext, v *node, ts time.Time, nodeGroupSize map[string]int, resourcesLeft resource.Limits, resourcesWithLimits []string, as scaledown.ActuationStatus) simulator.UnremovableReason {
144+
func (n *Nodes) unremovableReason(context *context.AutoscalingContext, scaleDownContext nodes.ScaleDownContext, v *node, ts time.Time, nodeGroupSize map[string]int) simulator.UnremovableReason {
145145
node := v.ntbr.Node
146146
// Check if node is marked with no scale down annotation.
147147
if eligibility.HasNoScaleDownAnnotation(node) {
@@ -182,17 +182,17 @@ func (n *Nodes) unremovableReason(context *context.AutoscalingContext, v *node,
182182
}
183183
}
184184

185-
if reason := verifyMinSize(node.Name, nodeGroup, nodeGroupSize, as); reason != simulator.NoReason {
185+
if reason := verifyMinSize(node.Name, nodeGroup, nodeGroupSize, scaleDownContext.ActuationStatus); reason != simulator.NoReason {
186186
return reason
187187
}
188188

189-
resourceDelta, err := n.limitsFinder.DeltaForNode(context, node, nodeGroup, resourcesWithLimits)
189+
resourceDelta, err := n.limitsFinder.DeltaForNode(context, node, nodeGroup, scaleDownContext.ResourcesWithLimits)
190190
if err != nil {
191191
klog.Errorf("Error getting node resources: %v", err)
192192
return simulator.UnexpectedError
193193
}
194194

195-
checkResult := resourcesLeft.TryDecrementBy(resourceDelta)
195+
checkResult := scaleDownContext.ResourcesLeft.TryDecrementBy(resourceDelta)
196196
if checkResult.Exceeded() {
197197
klog.V(4).Infof("Skipping %s - minimal limit exceeded for %v", node.Name, checkResult.ExceededResources)
198198
for _, resource := range checkResult.ExceededResources {

cluster-autoscaler/core/scaledown/unneeded/nodes_test.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828
"k8s.io/autoscaler/cluster-autoscaler/core/scaledown/resource"
2929
"k8s.io/autoscaler/cluster-autoscaler/core/scaledown/status"
3030
. "k8s.io/autoscaler/cluster-autoscaler/core/test"
31+
"k8s.io/autoscaler/cluster-autoscaler/processors/nodes"
3132
"k8s.io/autoscaler/cluster-autoscaler/simulator"
3233
kube_util "k8s.io/autoscaler/cluster-autoscaler/utils/kubernetes"
3334
. "k8s.io/autoscaler/cluster-autoscaler/utils/test"
@@ -188,10 +189,10 @@ func TestRemovableAt(t *testing.T) {
188189
})
189190
}
190191

191-
nodes := append(empty, drain...)
192+
removableNodes := append(empty, drain...)
192193
provider := testprovider.NewTestCloudProvider(nil, nil)
193194
provider.InsertNodeGroup(ng)
194-
for _, node := range nodes {
195+
for _, node := range removableNodes {
195196
provider.AddNode("ng", node.Node)
196197
}
197198

@@ -204,8 +205,12 @@ func TestRemovableAt(t *testing.T) {
204205
assert.NoError(t, err)
205206

206207
n := NewNodes(&fakeScaleDownTimeGetter{}, &resource.LimitsFinder{})
207-
n.Update(nodes, time.Now())
208-
gotEmptyToRemove, gotDrainToRemove, _ := n.RemovableAt(&ctx, time.Now(), resource.Limits{}, []string{}, as)
208+
n.Update(removableNodes, time.Now())
209+
gotEmptyToRemove, gotDrainToRemove, _ := n.RemovableAt(&ctx, nodes.ScaleDownContext{
210+
ActuationStatus: as,
211+
ResourcesLeft: resource.Limits{},
212+
ResourcesWithLimits: []string{},
213+
}, time.Now())
209214
if len(gotDrainToRemove) != tc.numDrainToRemove || len(gotEmptyToRemove) != tc.numEmptyToRemove {
210215
t.Errorf("%s: getNodesToRemove() return %d, %d, want %d, %d", tc.name, len(gotEmptyToRemove), len(gotDrainToRemove), tc.numEmptyToRemove, tc.numDrainToRemove)
211216
}

cluster-autoscaler/core/scaleup/orchestrator/orchestrator_test.go

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ import (
4646
"k8s.io/autoscaler/cluster-autoscaler/processors/nodegroupset"
4747
"k8s.io/autoscaler/cluster-autoscaler/processors/nodeinfosprovider"
4848
"k8s.io/autoscaler/cluster-autoscaler/processors/status"
49+
processorstest "k8s.io/autoscaler/cluster-autoscaler/processors/test"
4950
"k8s.io/autoscaler/cluster-autoscaler/utils/errors"
5051
kube_util "k8s.io/autoscaler/cluster-autoscaler/utils/kubernetes"
5152
"k8s.io/autoscaler/cluster-autoscaler/utils/taints"
@@ -1055,7 +1056,7 @@ func runSimpleScaleUpTest(t *testing.T, config *ScaleUpTestConfig) *ScaleUpTestR
10551056
assert.NoError(t, err)
10561057
clusterState := clusterstate.NewClusterStateRegistry(provider, clusterstate.ClusterStateRegistryConfig{}, context.LogRecorder, NewBackoff(), nodegroupconfig.NewDefaultNodeGroupConfigProcessor(options.NodeGroupDefaults), asyncnodegroups.NewDefaultAsyncNodeGroupStateChecker())
10571058
clusterState.UpdateNodes(nodes, nodeInfos, time.Now())
1058-
processors := NewTestProcessors(&context)
1059+
processors := processorstest.NewTestProcessors(&context)
10591060
processors.ScaleStateNotifier.Register(clusterState)
10601061
if config.EnableAutoprovisioning {
10611062
processors.NodeGroupListProcessor = &MockAutoprovisioningNodeGroupListProcessor{T: t}
@@ -1163,7 +1164,7 @@ func TestScaleUpUnhealthy(t *testing.T) {
11631164
clusterState.UpdateNodes(nodes, nodeInfos, time.Now())
11641165
p3 := BuildTestPod("p-new", 550, 0)
11651166

1166-
processors := NewTestProcessors(&context)
1167+
processors := processorstest.NewTestProcessors(&context)
11671168
suOrchestrator := New()
11681169
suOrchestrator.Initialize(&context, processors, clusterState, newEstimatorBuilder(), taints.TaintConfig{})
11691170
scaleUpStatus, err := suOrchestrator.ScaleUp([]*apiv1.Pod{p3}, nodes, []*appsv1.DaemonSet{}, nodeInfos, false)
@@ -1209,7 +1210,7 @@ func TestBinpackingLimiter(t *testing.T) {
12091210

12101211
extraPod := BuildTestPod("p-new", 500, 0)
12111212

1212-
processors := NewTestProcessors(&context)
1213+
processors := processorstest.NewTestProcessors(&context)
12131214

12141215
// We should stop binpacking after finding expansion option from first node group.
12151216
processors.BinpackingLimiter = &MockBinpackingLimiter{}
@@ -1263,7 +1264,7 @@ func TestScaleUpNoHelp(t *testing.T) {
12631264
clusterState.UpdateNodes(nodes, nodeInfos, time.Now())
12641265
p3 := BuildTestPod("p-new", 500, 0)
12651266

1266-
processors := NewTestProcessors(&context)
1267+
processors := processorstest.NewTestProcessors(&context)
12671268
suOrchestrator := New()
12681269
suOrchestrator.Initialize(&context, processors, clusterState, newEstimatorBuilder(), taints.TaintConfig{})
12691270
scaleUpStatus, err := suOrchestrator.ScaleUp([]*apiv1.Pod{p3}, nodes, []*appsv1.DaemonSet{}, nodeInfos, false)
@@ -1485,7 +1486,7 @@ func TestScaleUpBalanceGroups(t *testing.T) {
14851486
pods = append(pods, BuildTestPod(fmt.Sprintf("test-pod-%v", i), 80, 0))
14861487
}
14871488

1488-
processors := NewTestProcessors(&context)
1489+
processors := processorstest.NewTestProcessors(&context)
14891490
suOrchestrator := New()
14901491
suOrchestrator.Initialize(&context, processors, clusterState, newEstimatorBuilder(), taints.TaintConfig{})
14911492
scaleUpStatus, typedErr := suOrchestrator.ScaleUp(pods, nodes, []*appsv1.DaemonSet{}, nodeInfos, false)
@@ -1541,7 +1542,7 @@ func TestScaleUpAutoprovisionedNodeGroup(t *testing.T) {
15411542

15421543
clusterState := clusterstate.NewClusterStateRegistry(provider, clusterstate.ClusterStateRegistryConfig{}, context.LogRecorder, NewBackoff(), nodegroupconfig.NewDefaultNodeGroupConfigProcessor(config.NodeGroupAutoscalingOptions{MaxNodeProvisionTime: 15 * time.Minute}), asyncnodegroups.NewDefaultAsyncNodeGroupStateChecker())
15431544

1544-
processors := NewTestProcessors(&context)
1545+
processors := processorstest.NewTestProcessors(&context)
15451546
processors.NodeGroupListProcessor = &MockAutoprovisioningNodeGroupListProcessor{T: t}
15461547
processors.NodeGroupManager = &MockAutoprovisioningNodeGroupManager{T: t, ExtraGroups: 0}
15471548

@@ -1596,7 +1597,7 @@ func TestScaleUpBalanceAutoprovisionedNodeGroups(t *testing.T) {
15961597

15971598
clusterState := clusterstate.NewClusterStateRegistry(provider, clusterstate.ClusterStateRegistryConfig{}, context.LogRecorder, NewBackoff(), nodegroupconfig.NewDefaultNodeGroupConfigProcessor(config.NodeGroupAutoscalingOptions{MaxNodeProvisionTime: 15 * time.Minute}), asyncnodegroups.NewDefaultAsyncNodeGroupStateChecker())
15981599

1599-
processors := NewTestProcessors(&context)
1600+
processors := processorstest.NewTestProcessors(&context)
16001601
processors.NodeGroupListProcessor = &MockAutoprovisioningNodeGroupListProcessor{T: t}
16011602
processors.NodeGroupManager = &MockAutoprovisioningNodeGroupManager{T: t, ExtraGroups: 2}
16021603

@@ -1654,7 +1655,7 @@ func TestScaleUpToMeetNodeGroupMinSize(t *testing.T) {
16541655

16551656
nodes := []*apiv1.Node{n1, n2}
16561657
nodeInfos, _ := nodeinfosprovider.NewDefaultTemplateNodeInfoProvider(nil, false).Process(&context, nodes, []*appsv1.DaemonSet{}, taints.TaintConfig{}, time.Now())
1657-
processors := NewTestProcessors(&context)
1658+
processors := processorstest.NewTestProcessors(&context)
16581659
clusterState := clusterstate.NewClusterStateRegistry(provider, clusterstate.ClusterStateRegistryConfig{}, context.LogRecorder, NewBackoff(), nodegroupconfig.NewDefaultNodeGroupConfigProcessor(config.NodeGroupAutoscalingOptions{MaxNodeProvisionTime: 15 * time.Minute}), asyncnodegroups.NewDefaultAsyncNodeGroupStateChecker())
16591660
clusterState.UpdateNodes(nodes, nodeInfos, time.Now())
16601661

@@ -1746,7 +1747,7 @@ func TestScaleupAsyncNodeGroupsEnabled(t *testing.T) {
17461747

17471748
clusterState := clusterstate.NewClusterStateRegistry(provider, clusterstate.ClusterStateRegistryConfig{}, context.LogRecorder, NewBackoff(), nodegroupconfig.NewDefaultNodeGroupConfigProcessor(config.NodeGroupAutoscalingOptions{MaxNodeProvisionTime: 15 * time.Minute}), asyncnodegroups.NewDefaultAsyncNodeGroupStateChecker())
17481749

1749-
processors := NewTestProcessors(&context)
1750+
processors := processorstest.NewTestProcessors(&context)
17501751
processors.NodeGroupListProcessor = &MockAutoprovisioningNodeGroupListProcessor{T: t}
17511752
processors.NodeGroupManager = &MockAutoprovisioningNodeGroupManager{T: t, ExtraGroups: 0}
17521753
processors.AsyncNodeGroupStateChecker = &asyncnodegroups.MockAsyncNodeGroupStateChecker{IsUpcomingNodeGroup: tc.isUpcomingMockMap}

0 commit comments

Comments
 (0)