Skip to content

Commit 721b472

Browse files
authored
Merge pull request #6412 from XiShanYongYe-Chang/e2e-clustertaintpolicy
Add E2E for ClusterTaintPolicy controller
2 parents c97336c + cc39b22 commit 721b472

File tree

3 files changed

+316
-0
lines changed

3 files changed

+316
-0
lines changed
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
Copyright 2025 The Karmada 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 karmada
18+
19+
import (
20+
"context"
21+
"fmt"
22+
23+
"github.com/onsi/ginkgo/v2"
24+
"github.com/onsi/gomega"
25+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
26+
27+
policyv1alpha1 "github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1"
28+
karmada "github.com/karmada-io/karmada/pkg/generated/clientset/versioned"
29+
)
30+
31+
// CreateClusterTaintPolicy creates ClusterTaintPolicy with karmada client.
32+
func CreateClusterTaintPolicy(client karmada.Interface, policy *policyv1alpha1.ClusterTaintPolicy) {
33+
ginkgo.By(fmt.Sprintf("Creating ClusterTaintPolicy(%s)", policy.Name), func() {
34+
_, err := client.PolicyV1alpha1().ClusterTaintPolicies().Create(context.TODO(), policy, metav1.CreateOptions{})
35+
gomega.Expect(err).Should(gomega.Succeed())
36+
})
37+
}
38+
39+
// RemoveClusterTaintPolicy deletes ClusterTaintPolicy with karmada client.
40+
func RemoveClusterTaintPolicy(client karmada.Interface, name string) {
41+
ginkgo.By(fmt.Sprintf("Removing ClusterTaintPolicy(%s)", name), func() {
42+
err := client.PolicyV1alpha1().ClusterTaintPolicies().Delete(context.TODO(), name, metav1.DeleteOptions{})
43+
gomega.Expect(err).Should(gomega.Succeed())
44+
})
45+
}
Lines changed: 270 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,270 @@
1+
/*
2+
Copyright 2025 The Karmada 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 base
18+
19+
import (
20+
"fmt"
21+
22+
"github.com/onsi/ginkgo/v2"
23+
corev1 "k8s.io/api/core/v1"
24+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
25+
"k8s.io/apimachinery/pkg/util/rand"
26+
27+
clusterv1alpha1 "github.com/karmada-io/karmada/pkg/apis/cluster/v1alpha1"
28+
policyv1alpha1 "github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1"
29+
"github.com/karmada-io/karmada/pkg/util/helper"
30+
"github.com/karmada-io/karmada/test/e2e/framework"
31+
karmadaresource "github.com/karmada-io/karmada/test/e2e/framework/resource/karmada"
32+
)
33+
34+
// The following tests involve adding NoSchedule and NoExecute effect taints to clusters
35+
// in the test environment, which will impact the resource scheduling of other concurrently
36+
// executed test cases. Therefore, these tests need to be configured to run serially.
37+
var _ = framework.SerialDescribe("Taint cluster with ClusterTaintPolicy", func() {
38+
var policyName string
39+
var clusterTaintPolicy *policyv1alpha1.ClusterTaintPolicy
40+
var targetClusterName string
41+
42+
ginkgo.JustBeforeEach(func() {
43+
karmadaresource.CreateClusterTaintPolicy(karmadaClient, clusterTaintPolicy)
44+
ginkgo.DeferCleanup(func() {
45+
karmadaresource.RemoveClusterTaintPolicy(karmadaClient, policyName)
46+
})
47+
})
48+
49+
ginkgo.BeforeEach(func() {
50+
policyName = clusterTaintPolicyNamePrefix + rand.String(RandomStrLength)
51+
clusterTaintPolicy = &policyv1alpha1.ClusterTaintPolicy{
52+
TypeMeta: metav1.TypeMeta{
53+
APIVersion: policyv1alpha1.SchemeGroupVersion.String(),
54+
Kind: "ClusterTaintPolicy",
55+
},
56+
ObjectMeta: metav1.ObjectMeta{
57+
Name: policyName,
58+
},
59+
}
60+
})
61+
62+
ginkgo.Context("One condition match", func() {
63+
ginkgo.BeforeEach(func() {
64+
targetClusterName = framework.ClusterNames()[1]
65+
clusterTaintPolicy.Spec = policyv1alpha1.ClusterTaintPolicySpec{
66+
TargetClusters: &policyv1alpha1.ClusterAffinity{
67+
ClusterNames: []string{targetClusterName},
68+
},
69+
AddOnConditions: []policyv1alpha1.MatchCondition{
70+
{
71+
ConditionType: "NetworkReady",
72+
Operator: policyv1alpha1.MatchConditionOpIn,
73+
StatusValues: []metav1.ConditionStatus{metav1.ConditionFalse, metav1.ConditionUnknown},
74+
},
75+
},
76+
RemoveOnConditions: []policyv1alpha1.MatchCondition{
77+
{
78+
ConditionType: "NetworkReady",
79+
Operator: policyv1alpha1.MatchConditionOpIn,
80+
StatusValues: []metav1.ConditionStatus{metav1.ConditionTrue},
81+
},
82+
},
83+
Taints: []policyv1alpha1.Taint{
84+
{
85+
Key: "testing/network-not-ready",
86+
Effect: "NoSchedule",
87+
},
88+
},
89+
}
90+
})
91+
92+
ginkgo.It("taint should be added and removed upon single condition match", func() {
93+
ginkgo.By(fmt.Sprintf("update cluster(%s) NetworkReady condition to false", targetClusterName), func() {
94+
framework.UpdateClusterStatusCondition(karmadaClient, targetClusterName, metav1.Condition{
95+
Type: "NetworkReady",
96+
Status: metav1.ConditionFalse,
97+
})
98+
})
99+
100+
ginkgo.By(fmt.Sprintf("wait for the cluster(%s) taint added", targetClusterName), func() {
101+
framework.WaitClusterFitWith(controlPlaneClient, targetClusterName, func(cluster *clusterv1alpha1.Cluster) bool {
102+
return helper.TaintExists(cluster.Spec.Taints, &corev1.Taint{Key: "testing/network-not-ready", Effect: "NoSchedule"})
103+
})
104+
})
105+
106+
ginkgo.By(fmt.Sprintf("update cluster(%s) NetworkReady condition to true", targetClusterName), func() {
107+
framework.UpdateClusterStatusCondition(karmadaClient, targetClusterName, metav1.Condition{
108+
Type: "NetworkReady",
109+
Status: metav1.ConditionTrue,
110+
})
111+
})
112+
113+
ginkgo.By(fmt.Sprintf("wait for the cluster(%s) taint removed", targetClusterName), func() {
114+
framework.WaitClusterFitWith(controlPlaneClient, targetClusterName, func(cluster *clusterv1alpha1.Cluster) bool {
115+
return !helper.TaintExists(cluster.Spec.Taints, &corev1.Taint{Key: "testing/network-not-ready", Effect: "NoSchedule"})
116+
})
117+
})
118+
})
119+
120+
})
121+
122+
ginkgo.Context("Multi conditions match", func() {
123+
ginkgo.BeforeEach(func() {
124+
targetClusterName = framework.ClusterNames()[0]
125+
clusterTaintPolicy.Spec = policyv1alpha1.ClusterTaintPolicySpec{
126+
TargetClusters: &policyv1alpha1.ClusterAffinity{
127+
ClusterNames: []string{targetClusterName},
128+
},
129+
AddOnConditions: []policyv1alpha1.MatchCondition{
130+
{
131+
ConditionType: "NetworkReady",
132+
Operator: policyv1alpha1.MatchConditionOpIn,
133+
StatusValues: []metav1.ConditionStatus{metav1.ConditionFalse, metav1.ConditionUnknown},
134+
},
135+
{
136+
ConditionType: "StorageReady",
137+
Operator: policyv1alpha1.MatchConditionOpIn,
138+
StatusValues: []metav1.ConditionStatus{metav1.ConditionFalse, metav1.ConditionUnknown},
139+
},
140+
},
141+
RemoveOnConditions: []policyv1alpha1.MatchCondition{
142+
{
143+
ConditionType: "NetworkReady",
144+
Operator: policyv1alpha1.MatchConditionOpIn,
145+
StatusValues: []metav1.ConditionStatus{metav1.ConditionTrue},
146+
},
147+
{
148+
ConditionType: "StorageReady",
149+
Operator: policyv1alpha1.MatchConditionOpIn,
150+
StatusValues: []metav1.ConditionStatus{metav1.ConditionTrue},
151+
},
152+
},
153+
Taints: []policyv1alpha1.Taint{
154+
{
155+
Key: "testing/all-not-ready",
156+
Effect: "NoSchedule",
157+
},
158+
},
159+
}
160+
})
161+
162+
ginkgo.It("taint should be added and removed upon multi conditions match", func() {
163+
ginkgo.By(fmt.Sprintf("update cluster(%s) NetworkReady condition to false", targetClusterName), func() {
164+
framework.UpdateClusterStatusCondition(karmadaClient, targetClusterName, metav1.Condition{
165+
Type: "NetworkReady",
166+
Status: metav1.ConditionFalse,
167+
})
168+
})
169+
170+
ginkgo.By(fmt.Sprintf("update cluster(%s) StorageReady condition to false", targetClusterName), func() {
171+
framework.UpdateClusterStatusCondition(karmadaClient, targetClusterName, metav1.Condition{
172+
Type: "StorageReady",
173+
Status: metav1.ConditionFalse,
174+
})
175+
})
176+
177+
ginkgo.By(fmt.Sprintf("wait for the cluster(%s) taint added", targetClusterName), func() {
178+
framework.WaitClusterFitWith(controlPlaneClient, targetClusterName, func(cluster *clusterv1alpha1.Cluster) bool {
179+
return helper.TaintExists(cluster.Spec.Taints, &corev1.Taint{Key: "testing/all-not-ready", Effect: "NoSchedule"})
180+
})
181+
})
182+
183+
ginkgo.By(fmt.Sprintf("update cluster(%s) NetworkReady condition to true", targetClusterName), func() {
184+
framework.UpdateClusterStatusCondition(karmadaClient, targetClusterName, metav1.Condition{
185+
Type: "NetworkReady",
186+
Status: metav1.ConditionTrue,
187+
})
188+
})
189+
190+
ginkgo.By(fmt.Sprintf("update cluster(%s) StorageReady condition to true", targetClusterName), func() {
191+
framework.UpdateClusterStatusCondition(karmadaClient, targetClusterName, metav1.Condition{
192+
Type: "StorageReady",
193+
Status: metav1.ConditionTrue,
194+
})
195+
})
196+
197+
ginkgo.By(fmt.Sprintf("wait for the cluster(%s) taint removed", targetClusterName), func() {
198+
framework.WaitClusterFitWith(controlPlaneClient, targetClusterName, func(cluster *clusterv1alpha1.Cluster) bool {
199+
return !helper.TaintExists(cluster.Spec.Taints, &corev1.Taint{Key: "testing/all-not-ready", Effect: "NoSchedule"})
200+
})
201+
})
202+
})
203+
204+
})
205+
206+
ginkgo.Context("Control with multiple taints", func() {
207+
ginkgo.BeforeEach(func() {
208+
targetClusterName = framework.ClusterNames()[1]
209+
clusterTaintPolicy.Spec = policyv1alpha1.ClusterTaintPolicySpec{
210+
TargetClusters: &policyv1alpha1.ClusterAffinity{
211+
ClusterNames: []string{targetClusterName},
212+
},
213+
AddOnConditions: []policyv1alpha1.MatchCondition{
214+
{
215+
ConditionType: "NetworkReady",
216+
Operator: policyv1alpha1.MatchConditionOpIn,
217+
StatusValues: []metav1.ConditionStatus{metav1.ConditionFalse, metav1.ConditionUnknown},
218+
},
219+
},
220+
RemoveOnConditions: []policyv1alpha1.MatchCondition{
221+
{
222+
ConditionType: "NetworkReady",
223+
Operator: policyv1alpha1.MatchConditionOpIn,
224+
StatusValues: []metav1.ConditionStatus{metav1.ConditionTrue},
225+
},
226+
},
227+
Taints: []policyv1alpha1.Taint{
228+
{
229+
Key: "testing/network-not-ready",
230+
Effect: "NoSchedule",
231+
},
232+
{
233+
Key: "testing/network-not-ready",
234+
Effect: "NoExecute",
235+
},
236+
},
237+
}
238+
})
239+
240+
ginkgo.It("multiple taints should be added and removed upon conditions match", func() {
241+
ginkgo.By(fmt.Sprintf("update cluster(%s) NetworkReady condition to false", targetClusterName), func() {
242+
framework.UpdateClusterStatusCondition(karmadaClient, targetClusterName, metav1.Condition{
243+
Type: "NetworkReady",
244+
Status: metav1.ConditionFalse,
245+
})
246+
})
247+
248+
ginkgo.By(fmt.Sprintf("wait for the cluster(%s) taint added", targetClusterName), func() {
249+
framework.WaitClusterFitWith(controlPlaneClient, targetClusterName, func(cluster *clusterv1alpha1.Cluster) bool {
250+
return helper.TaintExists(cluster.Spec.Taints, &corev1.Taint{Key: "testing/network-not-ready", Effect: "NoSchedule"}) &&
251+
helper.TaintExists(cluster.Spec.Taints, &corev1.Taint{Key: "testing/network-not-ready", Effect: "NoExecute"})
252+
})
253+
})
254+
255+
ginkgo.By(fmt.Sprintf("update cluster(%s) NetworkReady condition to true", targetClusterName), func() {
256+
framework.UpdateClusterStatusCondition(karmadaClient, targetClusterName, metav1.Condition{
257+
Type: "NetworkReady",
258+
Status: metav1.ConditionTrue,
259+
})
260+
})
261+
262+
ginkgo.By(fmt.Sprintf("wait for the cluster(%s) taint removed", targetClusterName), func() {
263+
framework.WaitClusterFitWith(controlPlaneClient, targetClusterName, func(cluster *clusterv1alpha1.Cluster) bool {
264+
return !helper.TaintExists(cluster.Spec.Taints, &corev1.Taint{Key: "testing/network-not-ready", Effect: "NoSchedule"}) &&
265+
!helper.TaintExists(cluster.Spec.Taints, &corev1.Taint{Key: "testing/network-not-ready", Effect: "NoExecute"})
266+
})
267+
})
268+
})
269+
})
270+
})

test/e2e/suites/base/suite_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ const (
8585
cppNamePrefix = "cpp-"
8686
workloadRebalancerPrefix = "rebalancer-"
8787
remedyNamePrefix = "remedy-"
88+
clusterTaintPolicyNamePrefix = "ctp-"
8889

8990
updateDeploymentReplicas = 2
9091
updateStatefulSetReplicas = 2

0 commit comments

Comments
 (0)