1
16
17
18
19 package framework
20
21 import (
22 "context"
23 "fmt"
24 "testing"
25 "time"
26
27 v1 "k8s.io/api/core/v1"
28 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
29 "k8s.io/apimachinery/pkg/util/wait"
30 clientset "k8s.io/client-go/kubernetes"
31 "k8s.io/klog/v2"
32 nodectlr "k8s.io/kubernetes/pkg/controller/nodelifecycle"
33 )
34
35 const (
36
37 poll = 2 * time.Second
38
39
40
41 singleCallTimeout = 5 * time.Minute
42 )
43
44
45 func CreateNamespaceOrDie(c clientset.Interface, baseName string, t testing.TB) *v1.Namespace {
46 ns := &v1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: baseName}}
47 result, err := c.CoreV1().Namespaces().Create(context.TODO(), ns, metav1.CreateOptions{})
48 if err != nil {
49 t.Fatalf("Failed to create namespace: %v", err)
50 }
51 return result
52 }
53
54
55 func DeleteNamespaceOrDie(c clientset.Interface, ns *v1.Namespace, t testing.TB) {
56 err := c.CoreV1().Namespaces().Delete(context.TODO(), ns.Name, metav1.DeleteOptions{})
57 if err != nil {
58 t.Fatalf("Failed to delete namespace: %v", err)
59 }
60 }
61
62
63 func waitListAllNodes(c clientset.Interface) (*v1.NodeList, error) {
64 var nodes *v1.NodeList
65 var err error
66 if wait.PollImmediate(poll, singleCallTimeout, func() (bool, error) {
67 nodes, err = c.CoreV1().Nodes().List(context.TODO(), metav1.ListOptions{})
68 if err != nil {
69 return false, err
70 }
71 return true, nil
72 }) != nil {
73 return nodes, err
74 }
75 return nodes, nil
76 }
77
78
79
80 func Filter(nodeList *v1.NodeList, fn func(node v1.Node) bool) {
81 var l []v1.Node
82
83 for _, node := range nodeList.Items {
84 if fn(node) {
85 l = append(l, node)
86 }
87 }
88 nodeList.Items = l
89 }
90
91
92
93
94 func IsNodeSchedulable(node *v1.Node) bool {
95 if node == nil {
96 return false
97 }
98 return !node.Spec.Unschedulable && IsNodeReady(node)
99 }
100
101
102
103
104 func IsNodeReady(node *v1.Node) bool {
105 nodeReady := IsConditionSetAsExpected(node, v1.NodeReady, true)
106 networkReady := isConditionUnset(node, v1.NodeNetworkUnavailable) ||
107 IsConditionSetAsExpectedSilent(node, v1.NodeNetworkUnavailable, false)
108 return nodeReady && networkReady
109 }
110
111
112 func IsConditionSetAsExpected(node *v1.Node, conditionType v1.NodeConditionType, wantTrue bool) bool {
113 return isNodeConditionSetAsExpected(node, conditionType, wantTrue, false)
114 }
115
116
117 func IsConditionSetAsExpectedSilent(node *v1.Node, conditionType v1.NodeConditionType, wantTrue bool) bool {
118 return isNodeConditionSetAsExpected(node, conditionType, wantTrue, true)
119 }
120
121
122 func isConditionUnset(node *v1.Node, conditionType v1.NodeConditionType) bool {
123 for _, cond := range node.Status.Conditions {
124 if cond.Type == conditionType {
125 return false
126 }
127 }
128 return true
129 }
130
131
132 func isNodeConditionSetAsExpected(node *v1.Node, conditionType v1.NodeConditionType, wantTrue, silent bool) bool {
133
134 for _, cond := range node.Status.Conditions {
135
136 if cond.Type == conditionType {
137
138 if cond.Type == v1.NodeReady {
139 hasNodeControllerTaints := false
140
141 taints := node.Spec.Taints
142 for _, taint := range taints {
143 if taint.MatchTaint(nodectlr.UnreachableTaintTemplate) || taint.MatchTaint(nodectlr.NotReadyTaintTemplate) {
144 hasNodeControllerTaints = true
145 break
146 }
147 }
148 if wantTrue {
149 if (cond.Status == v1.ConditionTrue) && !hasNodeControllerTaints {
150 return true
151 }
152 msg := ""
153 if !hasNodeControllerTaints {
154 msg = fmt.Sprintf("Condition %s of node %s is %v instead of %t. Reason: %v, message: %v",
155 conditionType, node.Name, cond.Status == v1.ConditionTrue, wantTrue, cond.Reason, cond.Message)
156 } else {
157 msg = fmt.Sprintf("Condition %s of node %s is %v, but Node is tainted by NodeController with %v. Failure",
158 conditionType, node.Name, cond.Status == v1.ConditionTrue, taints)
159 }
160 if !silent {
161 klog.Infof(msg)
162 }
163 return false
164 }
165
166 if cond.Status != v1.ConditionTrue {
167 return true
168 }
169 if !silent {
170 klog.Infof("Condition %s of node %s is %v instead of %t. Reason: %v, message: %v",
171 conditionType, node.Name, cond.Status == v1.ConditionTrue, wantTrue, cond.Reason, cond.Message)
172 }
173 return false
174 }
175 if (wantTrue && (cond.Status == v1.ConditionTrue)) || (!wantTrue && (cond.Status != v1.ConditionTrue)) {
176 return true
177 }
178 if !silent {
179 klog.Infof("Condition %s of node %s is %v instead of %t. Reason: %v, message: %v",
180 conditionType, node.Name, cond.Status == v1.ConditionTrue, wantTrue, cond.Reason, cond.Message)
181 }
182 return false
183 }
184
185 }
186 if !silent {
187 klog.Infof("Couldn't find condition %v on node %v", conditionType, node.Name)
188 }
189 return false
190 }
191
View as plain text