Skip to content

Commit 5525dd6

Browse files
committed
Add n+3 test in e2e
Signed-off-by: smoshiur1237 <[email protected]>
1 parent 7a375f2 commit 5525dd6

File tree

4 files changed

+269
-3
lines changed

4 files changed

+269
-3
lines changed

scripts/ci-e2e.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,8 @@ if [[ "${CAPI_NIGHTLY_BUILD:-false}" == "true" ]]; then
6565
fi
6666

6767
case "${GINKGO_FOCUS:-}" in
68-
clusterctl-upgrade|k8s-upgrade|basic|integration|remediation|k8s-conformance|capi-md-tests)
69-
# if running basic, integration, k8s upgrade, clusterctl-upgrade, remediation, k8s conformance or capi-md tests, skip apply bmhs in dev-env
68+
clusterctl-upgrade|k8s-upgrade|k8s-upgrade-n3|basic|integration|remediation|k8s-conformance|capi-md-tests)
69+
# if running basic, integration, k8s upgrade, k8s n+3 upgrade, clusterctl-upgrade, remediation, k8s conformance or capi-md tests, skip apply bmhs in dev-env
7070
echo 'export SKIP_APPLY_BMH="true"' >>"${M3_DEV_ENV_PATH}/config_${USER}.sh"
7171
;;
7272

scripts/environment.sh

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,13 +74,24 @@ case "${GINKGO_FOCUS:-}" in
7474
export WORKER_MACHINE_COUNT=${WORKER_MACHINE_COUNT:-"1"}
7575
;;
7676

77-
# Pivoting, k8s-upgrade and remediation vars and config
77+
# Pivoting, k8s-upgrade, upgrade and remediation vars and config
7878
pivoting|k8s-upgrade|remediation)
7979
export NUM_NODES="4"
8080
export CONTROL_PLANE_MACHINE_COUNT=${CONTROL_PLANE_MACHINE_COUNT:-"3"}
8181
export WORKER_MACHINE_COUNT=${WORKER_MACHINE_COUNT:-"1"}
8282
;;
8383

84+
# k8s n+3 upgrade vars and config
85+
k8s-upgrade-n3)
86+
export NUM_NODES="4"
87+
export CONTROL_PLANE_MACHINE_COUNT=${CONTROL_PLANE_MACHINE_COUNT:-"3"}
88+
export WORKER_MACHINE_COUNT=${WORKER_MACHINE_COUNT:-"1"}
89+
export KUBERNETES_N0_VERSION=${KUBERNETES_N0_VERSION:-"v1.31.13"}
90+
export KUBERNETES_N1_VERSION=${KUBERNETES_N1_VERSION:-"v1.32.9"}
91+
export KUBERNETES_N2_VERSION=${KUBERNETES_N2_VERSION:-"v1.33.5"}
92+
export KUBERNETES_N3_VERSION=${KUBERNETES_N3_VERSION:-"v1.34.1"}
93+
;;
94+
8495
# Scalability test environment vars and config
8596
scalability)
8697
export NUM_NODES=${NUM_NODES:-"10"}

test/e2e/common.go

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1227,3 +1227,105 @@ func IsMetal3DataCountEqualToMachineCount(ctx context.Context, c client.Client,
12271227

12281228
return len(m3DataList.Items) == len(machineList.Items)
12291229
}
1230+
1231+
type UpgradeControlPlaneInput struct {
1232+
E2EConfig *clusterctl.E2EConfig
1233+
BootstrapClusterProxy framework.ClusterProxy
1234+
TargetCluster framework.ClusterProxy
1235+
SpecName string
1236+
ClusterName string
1237+
Namespace string
1238+
K8sToVersion string
1239+
K8sFromVersion string
1240+
}
1241+
1242+
func UpgradeControlPlane(ctx context.Context, inputGetter func() UpgradeControlPlaneInput) {
1243+
input := inputGetter()
1244+
e2eConfig := input.E2EConfig
1245+
clusterClient := input.BootstrapClusterProxy.GetClient()
1246+
targetClusterClient := input.TargetCluster.GetClient()
1247+
clientSet := input.TargetCluster.GetClientSet()
1248+
k8sToVersion := input.K8sToVersion
1249+
k8sFromVersion := input.K8sFromVersion
1250+
specName := input.SpecName
1251+
namespace := input.Namespace
1252+
clusterName := input.ClusterName
1253+
numberOfControlplane := int(*e2eConfig.MustGetInt32PtrVariable("CONTROL_PLANE_MACHINE_COUNT"))
1254+
var (
1255+
controlplaneTaints = []corev1.Taint{{Key: "node-role.kubernetes.io/control-plane", Effect: corev1.TaintEffectNoSchedule},
1256+
{Key: "node-role.kubernetes.io/master", Effect: corev1.TaintEffectNoSchedule}}
1257+
)
1258+
// Upgrade process starts here
1259+
// Download node image
1260+
By("Download image")
1261+
imageURL, imageChecksum := EnsureImage(k8sToVersion)
1262+
1263+
By("Create new KCP Metal3MachineTemplate with upgraded image to boot")
1264+
m3MachineTemplateName := clusterName + "-controlplane"
1265+
newM3MachineTemplateName := clusterName + "-new-controlplane"
1266+
CreateNewM3MachineTemplate(ctx, namespace, newM3MachineTemplateName, m3MachineTemplateName, clusterClient, imageURL, imageChecksum)
1267+
1268+
Byf("Update KCP to upgrade k8s version and binaries from %s to %s", k8sFromVersion, k8sToVersion)
1269+
kcpObj := framework.GetKubeadmControlPlaneByCluster(ctx, framework.GetKubeadmControlPlaneByClusterInput{
1270+
Lister: clusterClient,
1271+
ClusterName: clusterName,
1272+
Namespace: namespace,
1273+
})
1274+
helper, err := v1beta1patch.NewHelper(kcpObj, clusterClient)
1275+
Expect(err).NotTo(HaveOccurred())
1276+
kcpObj.Spec.MachineTemplate.Spec.InfrastructureRef.Name = newM3MachineTemplateName
1277+
kcpObj.Spec.Version = k8sToVersion
1278+
kcpObj.Spec.Rollout.Strategy.RollingUpdate.MaxSurge.IntVal = 0
1279+
Expect(helper.Patch(ctx, kcpObj)).To(Succeed())
1280+
1281+
Byf("Wait until %d BMH(s) are in deprovisioning state", 1)
1282+
WaitForNumBmhInState(ctx, bmov1alpha1.StateDeprovisioning, WaitForNumInput{
1283+
Client: clusterClient,
1284+
Options: []client.ListOption{client.InNamespace(namespace)},
1285+
Replicas: 1,
1286+
Intervals: e2eConfig.GetIntervals(specName, "wait-bmh-deprovisioning"),
1287+
})
1288+
1289+
Byf("Wait until three Control Plane machines become running and updated with the new %s k8s version", k8sToVersion)
1290+
runningAndUpgraded := func(machine clusterv1.Machine) bool {
1291+
running := machine.Status.GetTypedPhase() == clusterv1.MachinePhaseRunning
1292+
upgraded := machine.Spec.Version == k8sToVersion
1293+
return (running && upgraded)
1294+
}
1295+
WaitForNumMachines(ctx, runningAndUpgraded, WaitForNumInput{
1296+
Client: clusterClient,
1297+
Options: []client.ListOption{client.InNamespace(namespace)},
1298+
Replicas: numberOfControlplane,
1299+
Intervals: e2eConfig.GetIntervals(specName, "wait-machine-running"),
1300+
})
1301+
1302+
By("Untaint Control Plane nodes")
1303+
controlplaneNodes := getControlplaneNodes(ctx, clientSet)
1304+
untaintNodes(ctx, targetClusterClient, controlplaneNodes, controlplaneTaints)
1305+
1306+
By("Update maxSurge field in KubeadmControlPlane back to default value(1)")
1307+
kcpObj = framework.GetKubeadmControlPlaneByCluster(ctx, framework.GetKubeadmControlPlaneByClusterInput{
1308+
Lister: clusterClient,
1309+
ClusterName: clusterName,
1310+
Namespace: namespace,
1311+
})
1312+
helper, err = v1beta1patch.NewHelper(kcpObj, clusterClient)
1313+
Expect(err).NotTo(HaveOccurred())
1314+
kcpObj.Spec.Rollout.Strategy.RollingUpdate.MaxSurge.IntVal = 1
1315+
for range 3 {
1316+
err = helper.Patch(ctx, kcpObj)
1317+
if err == nil {
1318+
break
1319+
}
1320+
time.Sleep(30 * time.Second)
1321+
}
1322+
1323+
// Verify that all three control plane nodes are using the k8s version
1324+
Byf("Verify all three control plane machines become running and updated with new %s k8s version", k8sToVersion)
1325+
WaitForNumMachines(ctx, runningAndUpgraded, WaitForNumInput{
1326+
Client: clusterClient,
1327+
Options: []client.ListOption{client.InNamespace(namespace)},
1328+
Replicas: numberOfControlplane,
1329+
Intervals: e2eConfig.GetIntervals(specName, "wait-machine-running"),
1330+
})
1331+
}
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
package e2e
2+
3+
import (
4+
"context"
5+
"os"
6+
"path/filepath"
7+
"strings"
8+
9+
. "github.com/onsi/ginkgo/v2"
10+
. "github.com/onsi/gomega"
11+
"sigs.k8s.io/cluster-api/test/framework"
12+
"sigs.k8s.io/cluster-api/test/framework/clusterctl"
13+
"sigs.k8s.io/controller-runtime/pkg/client"
14+
)
15+
16+
var _ = Describe("Kubernetes version upgrade in target nodes", Label("k8s-upgrade-n3"), func() {
17+
18+
var (
19+
ctx = context.TODO()
20+
clusterctlLogFolder string
21+
)
22+
23+
BeforeEach(func() {
24+
osType = strings.ToLower(os.Getenv("OS"))
25+
Expect(osType).ToNot(Equal(""))
26+
validateGlobals(specName)
27+
28+
// We need to override clusterctl apply log folder to avoid getting our credentials exposed.
29+
clusterctlLogFolder = filepath.Join(os.TempDir(), "target_cluster_logs", bootstrapClusterProxy.GetName())
30+
})
31+
32+
It("Should create a cluster and run kubernetes N+3 tests", func() {
33+
By("Apply BMH for workload cluster")
34+
ApplyBmh(ctx, e2eConfig, bootstrapClusterProxy, namespace, specName)
35+
By("Creating target cluster")
36+
targetCluster, _ = CreateTargetCluster(ctx, func() CreateTargetClusterInput {
37+
return CreateTargetClusterInput{
38+
E2EConfig: e2eConfig,
39+
BootstrapClusterProxy: bootstrapClusterProxy,
40+
SpecName: specName,
41+
ClusterName: clusterName,
42+
K8sVersion: e2eConfig.MustGetVariable("KUBERNETES_N0_VERSION"),
43+
KCPMachineCount: int64(numberOfControlplane),
44+
WorkerMachineCount: int64(numberOfWorkers),
45+
ClusterctlLogFolder: clusterctlLogFolder,
46+
ClusterctlConfigPath: clusterctlConfigPath,
47+
OSType: osType,
48+
Namespace: namespace,
49+
}
50+
})
51+
52+
By("Running Kubernetes Upgrade tests")
53+
upgradeKubernetesN3(ctx, func() upgradeKubernetesN3Input {
54+
return upgradeKubernetesN3Input{
55+
E2EConfig: e2eConfig,
56+
BootstrapClusterProxy: bootstrapClusterProxy,
57+
TargetCluster: targetCluster,
58+
SpecName: specName,
59+
ClusterName: clusterName,
60+
Namespace: namespace,
61+
}
62+
})
63+
})
64+
65+
AfterEach(func() {
66+
ListBareMetalHosts(ctx, bootstrapClusterProxy.GetClient(), client.InNamespace(namespace))
67+
ListMetal3Machines(ctx, bootstrapClusterProxy.GetClient(), client.InNamespace(namespace))
68+
ListMachines(ctx, bootstrapClusterProxy.GetClient(), client.InNamespace(namespace))
69+
ListNodes(ctx, targetCluster.GetClient())
70+
DumpSpecResourcesAndCleanup(ctx, specName, bootstrapClusterProxy, targetCluster, artifactFolder, namespace, e2eConfig.GetIntervals, clusterName, clusterctlLogFolder, skipCleanup, clusterctlConfigPath)
71+
})
72+
73+
})
74+
75+
type upgradeKubernetesN3Input struct {
76+
E2EConfig *clusterctl.E2EConfig
77+
BootstrapClusterProxy framework.ClusterProxy
78+
TargetCluster framework.ClusterProxy
79+
SpecName string
80+
ClusterName string
81+
Namespace string
82+
}
83+
84+
// upgradeKubernetesN3 implements a test upgrading the cluster nodes from an old k8s version to a newer version.
85+
func upgradeKubernetesN3(ctx context.Context, inputGetter func() upgradeKubernetesN3Input) {
86+
Logf("Starting Kubernetes upgrade tests")
87+
input := inputGetter()
88+
clusterClient := input.BootstrapClusterProxy.GetClient()
89+
targetClusterClient := input.TargetCluster.GetClient()
90+
kubernetesVersion := input.E2EConfig.MustGetVariable("KUBERNETES_N0_VERSION")
91+
upgradedK8sVersion1 := input.E2EConfig.MustGetVariable("KUBERNETES_N1_VERSION")
92+
upgradedK8sVersion2 := input.E2EConfig.MustGetVariable("KUBERNETES_N2_VERSION")
93+
upgradedK8sVersion3 := input.E2EConfig.MustGetVariable("KUBERNETES_N3_VERSION")
94+
95+
Logf("KUBERNETES VERSION: %v", kubernetesVersion)
96+
Logf("UPGRADED K8S VERSION: %v", upgradedK8sVersion1)
97+
98+
ListBareMetalHosts(ctx, clusterClient, client.InNamespace(input.Namespace))
99+
ListMetal3Machines(ctx, clusterClient, client.InNamespace(namespace))
100+
ListMachines(ctx, clusterClient, client.InNamespace(namespace))
101+
ListNodes(ctx, targetClusterClient)
102+
103+
By("Running Kubernetes n+1 Upgrade tests")
104+
UpgradeControlPlane(ctx, func() UpgradeControlPlaneInput {
105+
return UpgradeControlPlaneInput{
106+
E2EConfig: e2eConfig,
107+
BootstrapClusterProxy: bootstrapClusterProxy,
108+
TargetCluster: targetCluster,
109+
SpecName: specName,
110+
ClusterName: clusterName,
111+
Namespace: namespace,
112+
K8sFromVersion: kubernetesVersion,
113+
K8sToVersion: upgradedK8sVersion1,
114+
}
115+
})
116+
By("KUBERNETES UPGRADE N+1 TESTS PASSED!")
117+
Logf("KUBERNETES VERSION: %v", upgradedK8sVersion1)
118+
Logf("UPGRADED K8S VERSION: %v", upgradedK8sVersion2)
119+
Logf("NUMBER OF CONTROLPLANE BMH: %v", numberOfControlplane)
120+
121+
By("Running Kubernetes N+2 Upgrade tests")
122+
UpgradeControlPlane(ctx, func() UpgradeControlPlaneInput {
123+
return UpgradeControlPlaneInput{
124+
E2EConfig: e2eConfig,
125+
BootstrapClusterProxy: bootstrapClusterProxy,
126+
TargetCluster: targetCluster,
127+
SpecName: specName,
128+
ClusterName: clusterName,
129+
Namespace: namespace,
130+
K8sFromVersion: upgradedK8sVersion1,
131+
K8sToVersion: upgradedK8sVersion2,
132+
}
133+
})
134+
By("KUBERNETES UPGRADE N+2 TESTS PASSED!")
135+
Logf("KUBERNETES VERSION: %v", upgradedK8sVersion2)
136+
Logf("UPGRADED K8S VERSION: %v", upgradedK8sVersion3)
137+
Logf("NUMBER OF CONTROLPLANE BMH: %v", numberOfControlplane)
138+
139+
By("Running Kubernetes n+3 Upgrade tests")
140+
UpgradeControlPlane(ctx, func() UpgradeControlPlaneInput {
141+
return UpgradeControlPlaneInput{
142+
E2EConfig: e2eConfig,
143+
BootstrapClusterProxy: bootstrapClusterProxy,
144+
TargetCluster: targetCluster,
145+
SpecName: specName,
146+
ClusterName: clusterName,
147+
Namespace: namespace,
148+
K8sFromVersion: upgradedK8sVersion2,
149+
K8sToVersion: upgradedK8sVersion3,
150+
}
151+
})
152+
By("KUBERNETES UPGRADE N+3 TESTS PASSED!")
153+
}

0 commit comments

Comments
 (0)