Skip to content

Commit 23d4f6f

Browse files
Merge pull request #22752 from sjenning/add-toleration-check-e2e
Bug: 1705649: test: extended: add check for pod tolerations
2 parents bb1b9b5 + eca90da commit 23d4f6f

1 file changed

Lines changed: 93 additions & 0 deletions

File tree

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
package operators
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
7+
. "github.com/onsi/ginkgo"
8+
9+
exutil "github.com/openshift/origin/test/extended/util"
10+
v1 "k8s.io/api/core/v1"
11+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
12+
"k8s.io/apimachinery/pkg/util/sets"
13+
schedulerapi "k8s.io/kubernetes/pkg/scheduler/api"
14+
e2e "k8s.io/kubernetes/test/e2e/framework"
15+
)
16+
17+
var _ = Describe("[Feature:Platform][Smoke] Managed cluster should", func() {
18+
oc := exutil.NewCLIWithoutNamespace("operators")
19+
20+
It("ensure control plane operators do not make themselves unevictable", func() {
21+
// iterate over the references to find valid images
22+
pods, err := oc.KubeFramework().ClientSet.CoreV1().Pods("").List(metav1.ListOptions{})
23+
if err != nil {
24+
e2e.Failf("unable to list pods: %v", err)
25+
}
26+
27+
// list of pods that use images not in the release payload
28+
invalidPodTolerations := sets.NewString()
29+
// a pod in a namespace that begins with kube-* or openshift-* must come from our release payload
30+
// TODO components in openshift-operators may not come from our payload, may want to weaken restriction
31+
namespacePrefixes := sets.NewString("kube-", "openshift-")
32+
excludedNamespaces := sets.NewString("openshift-kube-apiserver", "openshift-kube-controller-manager", "openshift-kube-scheduler", "openshift-etcd")
33+
// exclude these pods from checks
34+
whitelistPods := sets.NewString("network-operator", "dns-operator", "olm-operators")
35+
for _, pod := range pods.Items {
36+
// exclude non-control plane namespaces
37+
if !hasPrefixSet(pod.Namespace, namespacePrefixes) {
38+
continue
39+
}
40+
// exclude static pod managed namespaces
41+
if excludedNamespaces.Has(pod.Namespace) {
42+
continue
43+
}
44+
if hasPrefixSet(pod.Name, whitelistPods) {
45+
continue
46+
}
47+
// exclude pods started by DaemonSets
48+
if ownedByDaemonSet(pod) {
49+
continue
50+
}
51+
for _, toleration := range pod.Spec.Tolerations {
52+
if toleration.Operator == v1.TolerationOpExists {
53+
if toleration.Key == "" {
54+
invalidPodTolerations.Insert(fmt.Sprintf("%s/%s tolerates all taints", pod.Namespace, pod.Name))
55+
}
56+
if toleration.Key == schedulerapi.TaintNodeUnreachable || toleration.Key == schedulerapi.TaintNodeNotReady {
57+
if toleration.TolerationSeconds == nil {
58+
invalidPodTolerations.Insert(fmt.Sprintf("%s/%s tolerates %s with no tolerationSeconds", pod.Namespace, pod.Name, toleration.Key))
59+
}
60+
/* TODO enable this once we can get tolerationSeconds explicity defined in every component */
61+
/*if *toleration.TolerationSeconds == 300 {
62+
invalidPodTolerations.Insert(fmt.Sprintf("%s/%s tolerates %s with default tolerationSeconds", pod.Namespace, pod.Name, toleration.Key))
63+
}*/
64+
}
65+
}
66+
}
67+
}
68+
// log for debugging output before we ultimately fail
69+
//e2e.Logf("Pods found with invalid tolerations: %s", strings.Join(invalidPodTolerations.List(), "\n"))
70+
numInvalidPodTolerations := len(invalidPodTolerations)
71+
if numInvalidPodTolerations > 0 {
72+
e2e.Failf("\n%d pods found with invalid tolerations:\n%s", numInvalidPodTolerations, strings.Join(invalidPodTolerations.List(), "\n"))
73+
}
74+
})
75+
})
76+
77+
func hasPrefixSet(name string, set sets.String) bool {
78+
for _, prefix := range set.List() {
79+
if strings.HasPrefix(name, prefix) {
80+
return true
81+
}
82+
}
83+
return false
84+
}
85+
86+
func ownedByDaemonSet(pod v1.Pod) bool {
87+
for _, ownerRef := range pod.OwnerReferences {
88+
if ownerRef.Kind == "DaemonSet" {
89+
return true
90+
}
91+
}
92+
return false
93+
}

0 commit comments

Comments
 (0)