Skip to content

Commit 1e662ed

Browse files
Add node scaling measurement, nodescaling test
1 parent 2255db7 commit 1e662ed

File tree

8 files changed

+566
-0
lines changed

8 files changed

+566
-0
lines changed

clusterloader2/go.mod

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ replace (
3636
require (
3737
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.1
3838
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.1
39+
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0
40+
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.0
41+
github.com/aws/aws-sdk-go-v2 v1.36.3
42+
github.com/aws/aws-sdk-go-v2/config v1.29.14
43+
github.com/aws/aws-sdk-go-v2/service/autoscaling v1.53.0
3944
github.com/go-errors/errors v1.5.1
4045
github.com/google/go-cmp v0.7.0
4146
github.com/google/safetext v0.0.0-20230106111101-7156a760e523
@@ -66,6 +71,17 @@ require (
6671
cloud.google.com/go/compute/metadata v0.3.0 // indirect
6772
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 // indirect
6873
github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 // indirect
74+
github.com/aws/aws-sdk-go-v2/credentials v1.17.67 // indirect
75+
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 // indirect
76+
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 // indirect
77+
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 // indirect
78+
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect
79+
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 // indirect
80+
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 // indirect
81+
github.com/aws/aws-sdk-go-v2/service/sso v1.25.3 // indirect
82+
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.1 // indirect
83+
github.com/aws/aws-sdk-go-v2/service/sts v1.33.19 // indirect
84+
github.com/aws/smithy-go v1.22.2 // indirect
6985
github.com/beorn7/perks v1.0.1 // indirect
7086
github.com/blang/semver/v4 v4.0.0 // indirect
7187
github.com/cespare/xxhash/v2 v2.3.0 // indirect

clusterloader2/go.sum

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,34 @@ github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN
111111
github.com/aws/aws-sdk-go v1.34.28/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/+8rV9s48=
112112
github.com/aws/aws-sdk-go v1.38.3/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
113113
github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
114+
github.com/aws/aws-sdk-go-v2 v1.36.3 h1:mJoei2CxPutQVxaATCzDUjcZEjVRdpsiiXi2o38yqWM=
115+
github.com/aws/aws-sdk-go-v2 v1.36.3/go.mod h1:LLXuLpgzEbD766Z5ECcRmi8AzSwfZItDtmABVkRLGzg=
116+
github.com/aws/aws-sdk-go-v2/config v1.29.14 h1:f+eEi/2cKCg9pqKBoAIwRGzVb70MRKqWX4dg1BDcSJM=
117+
github.com/aws/aws-sdk-go-v2/config v1.29.14/go.mod h1:wVPHWcIFv3WO89w0rE10gzf17ZYy+UVS1Geq8Iei34g=
118+
github.com/aws/aws-sdk-go-v2/credentials v1.17.67 h1:9KxtdcIA/5xPNQyZRgUSpYOE6j9Bc4+D7nZua0KGYOM=
119+
github.com/aws/aws-sdk-go-v2/credentials v1.17.67/go.mod h1:p3C44m+cfnbv763s52gCqrjaqyPikj9Sg47kUVaNZQQ=
120+
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 h1:x793wxmUWVDhshP8WW2mlnXuFrO4cOd3HLBroh1paFw=
121+
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30/go.mod h1:Jpne2tDnYiFascUEs2AWHJL9Yp7A5ZVy3TNyxaAjD6M=
122+
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 h1:ZK5jHhnrioRkUNOc+hOgQKlUL5JeC3S6JgLxtQ+Rm0Q=
123+
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34/go.mod h1:p4VfIceZokChbA9FzMbRGz5OV+lekcVtHlPKEO0gSZY=
124+
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 h1:SZwFm17ZUNNg5Np0ioo/gq8Mn6u9w19Mri8DnJ15Jf0=
125+
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34/go.mod h1:dFZsC0BLo346mvKQLWmoJxT+Sjp+qcVR1tRVHQGOH9Q=
126+
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo=
127+
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo=
128+
github.com/aws/aws-sdk-go-v2/service/autoscaling v1.53.0 h1:uYhWKm7FhOKF5chyd2QSVXWqchI+ikht+aIkDJUIg9U=
129+
github.com/aws/aws-sdk-go-v2/service/autoscaling v1.53.0/go.mod h1:CDqMoc3KRdZJ8qziW96J35lKH01Wq3B2aihtHj2JbRs=
130+
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 h1:eAh2A4b5IzM/lum78bZ590jy36+d/aFLgKF/4Vd1xPE=
131+
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3/go.mod h1:0yKJC/kb8sAnmlYa6Zs3QVYqaC8ug2AbnNChv5Ox3uA=
132+
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 h1:dM9/92u2F1JbDaGooxTq18wmmFzbJRfXfVfy96/1CXM=
133+
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15/go.mod h1:SwFBy2vjtA0vZbjjaFtfN045boopadnoVPhu4Fv66vY=
134+
github.com/aws/aws-sdk-go-v2/service/sso v1.25.3 h1:1Gw+9ajCV1jogloEv1RRnvfRFia2cL6c9cuKV2Ps+G8=
135+
github.com/aws/aws-sdk-go-v2/service/sso v1.25.3/go.mod h1:qs4a9T5EMLl/Cajiw2TcbNt2UNo/Hqlyp+GiuG4CFDI=
136+
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.1 h1:hXmVKytPfTy5axZ+fYbR5d0cFmC3JvwLm5kM83luako=
137+
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.1/go.mod h1:MlYRNmYu/fGPoxBQVvBYr9nyr948aY/WLUvwBMBJubs=
138+
github.com/aws/aws-sdk-go-v2/service/sts v1.33.19 h1:1XuUZ8mYJw9B6lzAkXhqHlJd/XvaX32evhproijJEZY=
139+
github.com/aws/aws-sdk-go-v2/service/sts v1.33.19/go.mod h1:cQnB8CUnxbMU82JvlqjKR2HBOm3fe9pWorWBza6MBJ4=
140+
github.com/aws/smithy-go v1.22.2 h1:6D9hW43xKFrRx/tXXfAlIZc4JI+yQe6snnWcQyxSyLQ=
141+
github.com/aws/smithy-go v1.22.2/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg=
114142
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
115143
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
116144
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
/*
2+
Copyright 2025 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package common
18+
19+
import (
20+
"context"
21+
"errors"
22+
"fmt"
23+
"time"
24+
25+
"k8s.io/klog/v2"
26+
"k8s.io/perf-tests/clusterloader2/pkg/measurement"
27+
measurementutil "k8s.io/perf-tests/clusterloader2/pkg/measurement/util"
28+
"k8s.io/perf-tests/clusterloader2/pkg/provider"
29+
"k8s.io/perf-tests/clusterloader2/pkg/util"
30+
)
31+
32+
const (
33+
scaleNodesMeasurementName = "ScaleNodes"
34+
defaultScalingTimeout = 30 * time.Minute
35+
nodeCountCheckInterval = 30 * time.Second
36+
)
37+
38+
type scaleNodesMeasurement struct{}
39+
40+
func init() {
41+
if err := measurement.Register(scaleNodesMeasurementName, createScaleNodesMeasurement); err != nil {
42+
klog.Fatalf("Cannot register %s: %v", scaleNodesMeasurementName, err)
43+
}
44+
}
45+
46+
func createScaleNodesMeasurement() measurement.Measurement {
47+
return &scaleNodesMeasurement{}
48+
}
49+
50+
// Execute performs the node scaling operation with the specified parameters
51+
func (n *scaleNodesMeasurement) Execute(config *measurement.Config) ([]measurement.Summary, error) {
52+
// Get parameters from config.Params
53+
providerName, err := util.GetString(config.Params, "provider")
54+
if err != nil {
55+
return nil, err
56+
}
57+
region, err := util.GetString(config.Params, "region")
58+
if err != nil {
59+
return nil, err
60+
}
61+
clusterName, err := util.GetString(config.Params, "clusterName")
62+
if err != nil {
63+
return nil, err
64+
}
65+
batchSize, err := util.GetInt(config.Params, "batchSize")
66+
if err != nil {
67+
return nil, err
68+
}
69+
intervalSeconds, err := util.GetInt(config.Params, "intervalSeconds")
70+
if err != nil {
71+
return nil, err
72+
}
73+
targetNodeCount, err := util.GetInt(config.Params, "targetNodeCount")
74+
if err != nil {
75+
return nil, err
76+
}
77+
78+
// Get timeout with default value if not specified
79+
timeout, err := util.GetDurationOrDefault(config.Params, "timeout", defaultScalingTimeout)
80+
if err != nil {
81+
return nil, err
82+
}
83+
84+
// Initialize provider specific scaler
85+
scaler, err := provider.CreateNodeScaler(providerName, region, clusterName)
86+
if err != nil {
87+
return nil, fmt.Errorf("failed to create node scaler: %v", err)
88+
}
89+
90+
// Start scaling operation
91+
klog.Infof("Starting node scaling: target=%d, batchSize=%d/interval, interval=%ds, timeout=%v",
92+
targetNodeCount, batchSize, intervalSeconds, timeout)
93+
94+
// Start the scaling operation in a goroutine
95+
errCh := make(chan error)
96+
ctx, cancel := context.WithTimeout(context.Background(), timeout)
97+
defer cancel()
98+
go func() {
99+
errCh <- scaler.ScaleNodes(ctx, batchSize, intervalSeconds, targetNodeCount)
100+
}()
101+
102+
// Create stop channel for timeout
103+
stopCh := make(chan struct{})
104+
time.AfterFunc(timeout, func() {
105+
close(stopCh)
106+
})
107+
108+
// Set up options for waiting on nodes
109+
options := &measurementutil.WaitForNodeOptions{
110+
Selector: util.NewObjectSelector(),
111+
MinDesiredNodeCount: targetNodeCount,
112+
MaxDesiredNodeCount: targetNodeCount,
113+
CallerName: n.String(),
114+
WaitForNodesInterval: nodeCountCheckInterval,
115+
}
116+
117+
// Wait for either the scaling operation to fail or nodes to be ready
118+
select {
119+
case err := <-errCh:
120+
if err != nil {
121+
if errors.Is(err, context.DeadlineExceeded) {
122+
return nil, fmt.Errorf("scaling operation timed out after %v", timeout)
123+
}
124+
return nil, fmt.Errorf("failed to scale nodes: %v", err)
125+
}
126+
// Scaling operation completed, now wait for nodes to be ready
127+
if err := measurementutil.WaitForNodes(config.ClusterFramework.GetClientSets().GetClient(), stopCh, options); err != nil {
128+
return nil, err
129+
}
130+
return nil, nil
131+
case <-stopCh:
132+
return nil, fmt.Errorf("timeout while waiting for scaling operation to complete after %v", timeout)
133+
}
134+
}
135+
136+
// Dispose cleans up after the measurement.
137+
func (*scaleNodesMeasurement) Dispose() {}
138+
139+
// String returns string representation of this measurement.
140+
func (*scaleNodesMeasurement) String() string {
141+
return scaleNodesMeasurementName
142+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
Copyright 2025 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package provider
18+
19+
import (
20+
"fmt"
21+
22+
"k8s.io/perf-tests/clusterloader2/pkg/provider/scalers"
23+
"k8s.io/perf-tests/clusterloader2/pkg/provider/scalers/aws"
24+
)
25+
26+
// CreateNodeScaler creates a NodeScaler for the given provider
27+
func CreateNodeScaler(providerName, region, clusterName string) (scalers.NodeScaler, error) {
28+
switch providerName {
29+
case "aws":
30+
return aws.NewNodeScaler(region, clusterName)
31+
default:
32+
return nil, fmt.Errorf("unsupported provider for node scaling: %s", providerName)
33+
}
34+
}

0 commit comments

Comments
 (0)