Skip to content

Commit 6963dfa

Browse files
Add EKS clusterclass e2e suite
Signed-off-by: Alexandr Demicev <[email protected]> Co-authored-by: Richard Case <[email protected]>
1 parent 6b27d68 commit 6963dfa

File tree

8 files changed

+256
-8
lines changed

8 files changed

+256
-8
lines changed

templates/cluster-template-eks-clusterclass.yaml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,39 +7,39 @@ spec:
77
ref:
88
apiVersion: controlplane.cluster.x-k8s.io/v1beta2
99
kind: AWSManagedControlPlaneTemplate
10-
name: "${CLUSTER_NAME}-control-plane"
10+
name: "${CLUSTER_CLASS_NAME}-control-plane"
1111
infrastructure:
1212
ref:
1313
apiVersion: infrastructure.cluster.x-k8s.io/v1beta2
1414
kind: AWSManagedClusterTemplate
15-
name: "${CLUSTER_NAME}"
15+
name: "${CLUSTER_CLASS_NAME}"
1616
workers:
1717
machineDeployments:
1818
- class: default-worker
1919
template:
2020
bootstrap:
2121
ref:
22-
name: "${CLUSTER_NAME}-md-0"
22+
name: "${CLUSTER_CLASS_NAME}-md-0"
2323
apiVersion: bootstrap.cluster.x-k8s.io/v1beta2
2424
kind: EKSConfigTemplate
2525
infrastructure:
2626
ref:
27-
name: "${CLUSTER_NAME}-md-0"
27+
name: "${CLUSTER_CLASS_NAME}-md-0"
2828
apiVersion: infrastructure.cluster.x-k8s.io/v1beta2
2929
kind: AWSMachineTemplate
3030
---
3131
kind: AWSManagedClusterTemplate
3232
apiVersion: infrastructure.cluster.x-k8s.io/v1beta2
3333
metadata:
34-
name: "${CLUSTER_NAME}"
34+
name: "${CLUSTER_CLASS_NAME}"
3535
spec:
3636
template:
3737
spec: {}
3838
---
3939
kind: AWSManagedControlPlaneTemplate
4040
apiVersion: controlplane.cluster.x-k8s.io/v1beta2
4141
metadata:
42-
name: "${CLUSTER_NAME}-control-plane"
42+
name: "${CLUSTER_CLASS_NAME}-control-plane"
4343
spec:
4444
template:
4545
spec:
@@ -50,7 +50,7 @@ spec:
5050
apiVersion: infrastructure.cluster.x-k8s.io/v1beta2
5151
kind: AWSMachineTemplate
5252
metadata:
53-
name: "${CLUSTER_NAME}-md-0"
53+
name: "${CLUSTER_CLASS_NAME}-md-0"
5454
spec:
5555
template:
5656
spec:
@@ -61,6 +61,6 @@ spec:
6161
apiVersion: bootstrap.cluster.x-k8s.io/v1beta2
6262
kind: EKSConfigTemplate
6363
metadata:
64-
name: "${CLUSTER_NAME}-md-0"
64+
name: "${CLUSTER_CLASS_NAME}-md-0"
6565
spec:
6666
template: {}

test/e2e/data/e2e_eks_conf.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,8 @@ providers:
116116
targetName: "cluster-template-eks-control-plane-only-legacy.yaml"
117117
- sourcePath: "./eks/cluster-template-eks-control-plane-bare-eks.yaml"
118118
targetName: "cluster-template-eks-control-plane-bare-eks.yaml"
119+
- sourcePath: "./infrastructure-aws/withclusterclass/kustomize_sources/eks-clusterclass/clusterclass-eks-e2e.yaml"
120+
- sourcePath: "./infrastructure-aws/withclusterclass/generated/cluster-template-eks-clusterclass.yaml"
119121

120122
variables:
121123
KUBERNETES_VERSION: "v1.32.0"
@@ -125,6 +127,7 @@ variables:
125127
EXP_MACHINE_POOL: "true"
126128
EXP_MACHINE_POOL_MACHINES: "true"
127129
EXP_CLUSTER_RESOURCE_SET: "true"
130+
CLUSTER_TOPOLOGY: "true"
128131
EVENT_BRIDGE_INSTANCE_STATE: "true"
129132
AWS_NODE_MACHINE_TYPE: t3.large
130133
AWS_MACHINE_TYPE_VCPU_USAGE: 2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
apiVersion: cluster.x-k8s.io/v1beta1
2+
kind: Cluster
3+
metadata:
4+
name: "${CLUSTER_NAME}"
5+
spec:
6+
clusterNetwork:
7+
pods:
8+
cidrBlocks:
9+
- 192.168.0.0/16
10+
topology:
11+
class: eks-e2e
12+
version: "${KUBERNETES_VERSION}"
13+
workers:
14+
machineDeployments:
15+
- class: default-worker
16+
name: md-0
17+
replicas: ${WORKER_MACHINE_COUNT}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
apiVersion: cluster.x-k8s.io/v1beta1
2+
kind: ClusterClass
3+
metadata:
4+
name: eks-e2e
5+
spec:
6+
controlPlane:
7+
ref:
8+
apiVersion: controlplane.cluster.x-k8s.io/v1beta2
9+
kind: AWSManagedControlPlaneTemplate
10+
name: "${CLUSTER_NAME}-control-plane"
11+
infrastructure:
12+
ref:
13+
apiVersion: infrastructure.cluster.x-k8s.io/v1beta2
14+
kind: AWSManagedClusterTemplate
15+
name: "${CLUSTER_NAME}"
16+
workers:
17+
machineDeployments:
18+
- class: default-worker
19+
template:
20+
bootstrap:
21+
ref:
22+
name: "${CLUSTER_NAME}-md-0"
23+
apiVersion: bootstrap.cluster.x-k8s.io/v1beta2
24+
kind: EKSConfigTemplate
25+
infrastructure:
26+
ref:
27+
name: "${CLUSTER_NAME}-md-0"
28+
apiVersion: infrastructure.cluster.x-k8s.io/v1beta2
29+
kind: AWSMachineTemplate
30+
---
31+
kind: AWSManagedClusterTemplate
32+
apiVersion: infrastructure.cluster.x-k8s.io/v1beta2
33+
metadata:
34+
name: "${CLUSTER_NAME}"
35+
spec:
36+
template:
37+
spec: {}
38+
---
39+
kind: AWSManagedControlPlaneTemplate
40+
apiVersion: controlplane.cluster.x-k8s.io/v1beta2
41+
metadata:
42+
name: "${CLUSTER_NAME}-control-plane"
43+
spec:
44+
template:
45+
spec:
46+
region: "${AWS_REGION}"
47+
sshKeyName: "${AWS_SSH_KEY_NAME}"
48+
version: "${KUBERNETES_VERSION}"
49+
---
50+
apiVersion: infrastructure.cluster.x-k8s.io/v1beta2
51+
kind: AWSMachineTemplate
52+
metadata:
53+
name: "${CLUSTER_NAME}-md-0"
54+
spec:
55+
template:
56+
spec:
57+
instanceType: "${AWS_NODE_MACHINE_TYPE}"
58+
iamInstanceProfile: "nodes.cluster-api-provider-aws.sigs.k8s.io"
59+
sshKeyName: "${AWS_SSH_KEY_NAME}"
60+
---
61+
apiVersion: bootstrap.cluster.x-k8s.io/v1beta2
62+
kind: EKSConfigTemplate
63+
metadata:
64+
name: "${CLUSTER_NAME}-md-0"
65+
spec:
66+
template: {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
resources:
2+
- cluster-template.yaml
3+
generatorOptions:
4+
disableNameSuffixHash: true
5+
labels:
6+
type: generated
7+
annotations:
8+
note: generated
9+

test/e2e/suites/managed/control_plane_helpers.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,14 @@ import (
2828
ekstypes "github.com/aws/aws-sdk-go-v2/service/eks/types"
2929
. "github.com/onsi/ginkgo/v2"
3030
. "github.com/onsi/gomega"
31+
corev1 "k8s.io/api/core/v1"
3132
"k8s.io/apimachinery/pkg/util/version"
3233
crclient "sigs.k8s.io/controller-runtime/pkg/client"
3334

3435
ekscontrolplanev1 "sigs.k8s.io/cluster-api-provider-aws/v2/controlplane/eks/api/v1beta2"
36+
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
3537
"sigs.k8s.io/cluster-api/test/framework"
38+
clusterctl "sigs.k8s.io/cluster-api/test/framework/clusterctl"
3639
)
3740

3841
type waitForControlPlaneToBeUpgradedInput struct {
@@ -93,3 +96,73 @@ func GetControlPlaneByName(ctx context.Context, input GetControlPlaneByNameInput
9396
Expect(input.Getter.Get(ctx, key, cp)).To(Succeed(), "Failed to get AWSManagedControlPlane object %s/%s", input.Namespace, input.Name)
9497
return cp
9598
}
99+
100+
func WaitForEKSControlPlaneInitialized(ctx context.Context, input clusterctl.ApplyCustomClusterTemplateAndWaitInput, result *clusterctl.ApplyCustomClusterTemplateAndWaitResult) {
101+
Expect(ctx).NotTo(BeNil(), "ctx is required for WaitForEKSControlPlaneInitialized")
102+
Expect(input.ClusterProxy).ToNot(BeNil(), "Invalid argument. input.ClusterProxy can't be nil")
103+
104+
var awsCP ekscontrolplanev1.AWSManagedControlPlane
105+
Eventually(func(g Gomega) {
106+
list, err := listAWSManagedControlPlanes(ctx, input.ClusterProxy.GetClient(), result.Cluster.Namespace, result.Cluster.Name)
107+
g.Expect(err).To(Succeed(), "failed to list AWSManagedControlPlane resource")
108+
109+
g.Expect(len(list.Items)).To(Equal(1),
110+
"expected exactly one AWSManagedControlPlane for %s/%s",
111+
result.Cluster.Namespace, result.Cluster.Name,
112+
)
113+
awsCP = list.Items[0]
114+
}, 10*time.Second, 1*time.Second).Should(Succeed())
115+
116+
key := crclient.ObjectKey{Namespace: awsCP.Namespace, Name: awsCP.Name}
117+
waitForControlPlaneReady(ctx, input.ClusterProxy.GetClient(), key, input.WaitForControlPlaneIntervals...)
118+
}
119+
120+
func WaitForEKSControlPlaneMachinesReady(ctx context.Context, input clusterctl.ApplyCustomClusterTemplateAndWaitInput, result *clusterctl.ApplyCustomClusterTemplateAndWaitResult) {
121+
Expect(ctx).NotTo(BeNil(), "ctx is required for WaitForEKSControlPlaneMachinesReady")
122+
Expect(input.ClusterProxy).ToNot(BeNil(), "input.ClusterProxy can't be nil")
123+
124+
var awsCP ekscontrolplanev1.AWSManagedControlPlane
125+
Eventually(func(g Gomega) {
126+
list, err := listAWSManagedControlPlanes(ctx, input.ClusterProxy.GetClient(), result.Cluster.Namespace, result.Cluster.Name)
127+
g.Expect(err).To(Succeed())
128+
awsCP = list.Items[0]
129+
130+
g.Expect(awsCP.Status.Ready).To(BeTrue(),
131+
"waiting for AWSManagedControlPlane %s/%s to become Ready",
132+
awsCP.Namespace, awsCP.Name,
133+
)
134+
}, input.WaitForControlPlaneIntervals...).Should(Succeed())
135+
136+
workloadClusterProxy := input.ClusterProxy.GetWorkloadCluster(ctx, result.Cluster.Namespace, input.ClusterName)
137+
waitForWorkloadClusterReachable(ctx, workloadClusterProxy.GetClient(), input.WaitForControlPlaneIntervals...)
138+
}
139+
140+
// listAWSManagedControlPlanes returns a list of AWSManagedControlPlanes for the given cluster.
141+
func listAWSManagedControlPlanes(ctx context.Context, client crclient.Client, namespace, clusterName string) (*ekscontrolplanev1.AWSManagedControlPlaneList, error) {
142+
list := &ekscontrolplanev1.AWSManagedControlPlaneList{}
143+
err := client.List(ctx, list,
144+
crclient.InNamespace(namespace),
145+
crclient.MatchingLabels{clusterv1.ClusterNameLabel: clusterName},
146+
)
147+
return list, err
148+
}
149+
150+
// waitForControlPlaneReady polls until the given AWSManagedControlPlane is marked Ready.
151+
func waitForControlPlaneReady(ctx context.Context, client crclient.Client, key crclient.ObjectKey, intervals ...interface{}) {
152+
Eventually(func(g Gomega) {
153+
var latest ekscontrolplanev1.AWSManagedControlPlane
154+
g.Expect(client.Get(ctx, key, &latest)).To(Succeed())
155+
g.Expect(latest.Status.Ready).To(BeTrue(),
156+
"AWSManagedControlPlane %s/%s is not Ready", key.Namespace, key.Name,
157+
)
158+
}, intervals...).Should(Succeed())
159+
}
160+
161+
// waitForWorkloadClusterReachable checks when the kube-system namespace is reachable in the workload cluster.
162+
func waitForWorkloadClusterReachable(ctx context.Context, client crclient.Client, intervals ...interface{}) {
163+
Eventually(func(g Gomega) {
164+
ns := &corev1.Namespace{}
165+
g.Expect(client.Get(ctx, crclient.ObjectKey{Name: "kube-system"}, ns)).
166+
To(Succeed(), "workload API server not yet reachable")
167+
}, intervals...).Should(Succeed())
168+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
//go:build e2e
2+
// +build e2e
3+
4+
/*
5+
Copyright 2025 The Kubernetes Authors.
6+
7+
Licensed under the Apache License, Version 2.0 (the "License");
8+
you may not use this file except in compliance with the License.
9+
You may obtain a copy of the License at
10+
11+
http://www.apache.org/licenses/LICENSE-2.0
12+
13+
Unless required by applicable law or agreed to in writing, software
14+
distributed under the License is distributed on an "AS IS" BASIS,
15+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
See the License for the specific language governing permissions and
17+
limitations under the License.
18+
*/
19+
20+
package managed
21+
22+
import (
23+
"context"
24+
"fmt"
25+
26+
"github.com/onsi/ginkgo/v2"
27+
. "github.com/onsi/gomega"
28+
"k8s.io/utils/ptr"
29+
30+
ekscontrolplanev1 "sigs.k8s.io/cluster-api-provider-aws/v2/controlplane/eks/api/v1beta2"
31+
"sigs.k8s.io/cluster-api-provider-aws/v2/test/e2e/shared"
32+
capi_e2e "sigs.k8s.io/cluster-api/test/e2e"
33+
"sigs.k8s.io/cluster-api/test/framework/clusterctl"
34+
"sigs.k8s.io/cluster-api/util"
35+
)
36+
37+
var _ = ginkgo.Describe("[managed] [general] EKS clusterclass tests", func() {
38+
const specName = "cluster"
39+
var (
40+
ctx context.Context
41+
clusterName string
42+
)
43+
44+
ginkgo.BeforeEach(func() {
45+
ctx = context.TODO()
46+
47+
if !runGeneralTests() {
48+
ginkgo.Skip("skipping due to unmet condition")
49+
}
50+
51+
ginkgo.By("should have a valid test configuration")
52+
Expect(e2eCtx.Environment.BootstrapClusterProxy).ToNot(BeNil(), "BootstrapClusterProxy can't be nil")
53+
Expect(e2eCtx.E2EConfig).ToNot(BeNil(), "E2EConfig can't be nil")
54+
Expect(e2eCtx.E2EConfig.Variables).To(HaveKey(shared.KubernetesVersion))
55+
Expect(e2eCtx.E2EConfig.Variables).To(HaveKey(shared.CNIAddonVersion))
56+
57+
clusterName = fmt.Sprintf("%s-%s", specName, util.RandomString(6))
58+
59+
ginkgo.By("default iam role should exist")
60+
VerifyRoleExistsAndOwned(ctx, ekscontrolplanev1.DefaultEKSControlPlaneRole, "", false, e2eCtx.AWSSessionV2)
61+
})
62+
63+
capi_e2e.QuickStartSpec(context.TODO(), func() capi_e2e.QuickStartSpecInput {
64+
return capi_e2e.QuickStartSpecInput{
65+
E2EConfig: e2eCtx.E2EConfig,
66+
ClusterctlConfigPath: e2eCtx.Environment.ClusterctlConfigPath,
67+
BootstrapClusterProxy: e2eCtx.Environment.BootstrapClusterProxy,
68+
ArtifactFolder: e2eCtx.Settings.ArtifactFolder,
69+
SkipCleanup: e2eCtx.Settings.SkipCleanup,
70+
Flavor: ptr.To(EKSClusterClassFlavor),
71+
ClusterName: ptr.To(clusterName),
72+
WorkerMachineCount: ptr.To(int64(3)),
73+
ControlPlaneWaiters: clusterctl.ControlPlaneWaiters{
74+
WaitForControlPlaneInitialized: WaitForEKSControlPlaneInitialized,
75+
WaitForControlPlaneMachinesReady: WaitForEKSControlPlaneMachinesReady,
76+
},
77+
}
78+
})
79+
})

test/e2e/suites/managed/helpers.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ const (
4949
EKSMachinePoolOnlyFlavor = "eks-machinepool-only"
5050
EKSIPv6ClusterFlavor = "eks-ipv6-cluster"
5151
EKSControlPlaneOnlyLegacyFlavor = "eks-control-plane-only-legacy"
52+
EKSClusterClassFlavor = "eks-clusterclass"
5253
)
5354

5455
const (

0 commit comments

Comments
 (0)