Skip to content

Commit 59cda90

Browse files
authoredSep 17, 2022
test: Watch pods and nodes during tests (#2525)
1 parent 2683460 commit 59cda90

File tree

3 files changed

+89
-20
lines changed

3 files changed

+89
-20
lines changed
 

‎test/pkg/environment/expectations.go

+87-18
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ import (
3333
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3434
"k8s.io/apimachinery/pkg/labels"
3535
"k8s.io/apimachinery/pkg/types"
36+
"k8s.io/client-go/informers"
37+
"k8s.io/client-go/tools/cache"
3638
"knative.dev/pkg/logging"
3739
"knative.dev/pkg/ptr"
3840
"sigs.k8s.io/controller-runtime/pkg/client"
@@ -61,14 +63,29 @@ var (
6163
}
6264
)
6365

66+
const (
67+
NoWatch = "NoWatch"
68+
)
69+
6470
// if set, logs additional information that may be useful in debugging an E2E test failure
6571
var debugE2E = true
72+
var stop chan struct{}
6673

74+
// nolint:gocyclo
6775
func (env *Environment) BeforeEach() {
76+
stop = make(chan struct{})
77+
78+
if debugE2E {
79+
fmt.Println("------- START BEFORE -------")
80+
defer fmt.Println("------- END BEFORE -------")
81+
}
82+
6883
var nodes v1.NodeList
6984
Expect(env.Client.List(env.Context, &nodes)).To(Succeed())
7085
if debugE2E {
71-
env.dumpNodeInformation(nodes)
86+
for i := range nodes.Items {
87+
fmt.Println(env.getNodeInformation(&nodes.Items[i]))
88+
}
7289
}
7390
for _, node := range nodes.Items {
7491
if len(node.Spec.Taints) == 0 && !node.Spec.Unschedulable {
@@ -79,41 +96,92 @@ func (env *Environment) BeforeEach() {
7996
var pods v1.PodList
8097
Expect(env.Client.List(env.Context, &pods)).To(Succeed())
8198
if debugE2E {
82-
env.dumpPodInformation(pods)
99+
for i := range pods.Items {
100+
fmt.Println(env.getPodInformation(&pods.Items[i]))
101+
}
83102
}
84103
for i := range pods.Items {
85104
Expect(pod.IsProvisionable(&pods.Items[i])).To(BeFalse(),
86105
fmt.Sprintf("expected to have no provisionable pods, found %s/%s", pods.Items[i].Namespace, pods.Items[i].Name))
87106
Expect(pods.Items[i].Namespace).ToNot(Equal("default"),
88107
fmt.Sprintf("expected no pods in the `default` namespace, found %s/%s", pods.Items[i].Namespace, pods.Items[i].Name))
89108
}
109+
// If the test is labeled as NoWatch, then the node/pod monitor will just list at the beginning
110+
// of the test rather than perform a watch during it
111+
if debugE2E && !lo.Contains(CurrentSpecReport().Labels(), NoWatch) {
112+
env.startNodeMonitor(stop)
113+
env.startPodMonitor(stop)
114+
}
90115
var provisioners v1alpha5.ProvisionerList
91116
Expect(env.Client.List(env.Context, &provisioners)).To(Succeed())
92117
Expect(provisioners.Items).To(HaveLen(0), "expected no provisioners to exist")
93118
env.Monitor.Reset()
94119
env.StartingNodeCount = env.Monitor.NodeCountAtReset()
95120
}
96121

97-
func (env *Environment) dumpNodeInformation(nodes v1.NodeList) {
98-
for i := range nodes.Items {
99-
node := nodes.Items[i]
100-
pods, _ := nodeutils.GetNodePods(env, env.Client, &node)
101-
fmt.Printf("node %s ready=%s initialized=%s pods=%d taints = %v\n", node.Name, nodeutils.GetCondition(&node, v1.NodeReady).Status, node.Labels[v1alpha5.LabelNodeInitialized], len(pods), node.Spec.Taints)
102-
}
122+
func (env *Environment) getNodeInformation(n *v1.Node) string {
123+
pods, _ := nodeutils.GetNodePods(env, env.Client, n)
124+
return fmt.Sprintf("node %s ready=%s initialized=%s pods=%d taints=%v", n.Name, nodeutils.GetCondition(n, v1.NodeReady).Status, n.Labels[v1alpha5.LabelNodeInitialized], len(pods), n.Spec.Taints)
103125
}
104126

105-
func (env *Environment) dumpPodInformation(pods v1.PodList) {
106-
for i, p := range pods.Items {
107-
var containerInfo strings.Builder
108-
for _, c := range p.Status.ContainerStatuses {
109-
if containerInfo.Len() > 0 {
110-
fmt.Fprintf(&containerInfo, ", ")
111-
}
112-
fmt.Fprintf(&containerInfo, "%s restarts=%d", c.Name, c.RestartCount)
127+
func (env *Environment) getPodInformation(p *v1.Pod) string {
128+
var containerInfo strings.Builder
129+
for _, c := range p.Status.ContainerStatuses {
130+
if containerInfo.Len() > 0 {
131+
fmt.Fprintf(&containerInfo, ", ")
113132
}
114-
fmt.Printf("pods %s/%s provisionable=%v nodename=%s [%s]\n", p.Namespace, p.Name,
115-
pod.IsProvisionable(&pods.Items[i]), p.Spec.NodeName, containerInfo.String())
133+
fmt.Fprintf(&containerInfo, "%s restarts=%d", c.Name, c.RestartCount)
116134
}
135+
return fmt.Sprintf("pods %s/%s provisionable=%v phase=%s nodename=%s [%s]", p.Namespace, p.Name,
136+
pod.IsProvisionable(p), p.Status.Phase, p.Spec.NodeName, containerInfo.String())
137+
}
138+
139+
// startPodMonitor monitors all pods that are provisioned in a namespace outside kube-system
140+
// and karpenter namespaces during a test
141+
func (env *Environment) startPodMonitor(stop <-chan struct{}) {
142+
factory := informers.NewSharedInformerFactoryWithOptions(env.KubeClient, time.Second*30,
143+
informers.WithTweakListOptions(func(l *metav1.ListOptions) {
144+
l.FieldSelector = "metadata.namespace!=kube-system,metadata.namespace!=karpenter"
145+
}))
146+
podInformer := factory.Core().V1().Pods().Informer()
147+
podInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
148+
AddFunc: func(obj interface{}) {
149+
fmt.Printf("[CREATED] %s\n", env.getPodInformation(obj.(*v1.Pod)))
150+
},
151+
UpdateFunc: func(oldObj interface{}, newObj interface{}) {
152+
if env.getPodInformation(oldObj.(*v1.Pod)) != env.getPodInformation(newObj.(*v1.Pod)) {
153+
fmt.Printf("[UPDATED] %s\n", env.getPodInformation(newObj.(*v1.Pod)))
154+
}
155+
},
156+
DeleteFunc: func(obj interface{}) {
157+
fmt.Printf("[DELETED] %s\n", env.getPodInformation(obj.(*v1.Pod)))
158+
},
159+
})
160+
factory.Start(stop)
161+
}
162+
163+
// startNodeMonitor monitors all nodes that are provisioned by any provisioners during a test
164+
func (env *Environment) startNodeMonitor(stop <-chan struct{}) {
165+
factory := informers.NewSharedInformerFactoryWithOptions(env.KubeClient, time.Second*30,
166+
informers.WithTweakListOptions(func(l *metav1.ListOptions) { l.LabelSelector = v1alpha5.ProvisionerNameLabelKey }))
167+
podInformer := factory.Core().V1().Nodes().Informer()
168+
podInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
169+
AddFunc: func(obj interface{}) {
170+
node := obj.(*v1.Node)
171+
if _, ok := node.Labels[TestLabelName]; ok {
172+
fmt.Printf("[CREATED] %s\n", env.getNodeInformation(obj.(*v1.Node)))
173+
}
174+
},
175+
UpdateFunc: func(oldObj interface{}, newObj interface{}) {
176+
if env.getNodeInformation(oldObj.(*v1.Node)) != env.getNodeInformation(newObj.(*v1.Node)) {
177+
fmt.Printf("[UPDATED] %s\n", env.getNodeInformation(newObj.(*v1.Node)))
178+
}
179+
},
180+
DeleteFunc: func(obj interface{}) {
181+
fmt.Printf("[DELETED] %s\n", env.getNodeInformation(obj.(*v1.Node)))
182+
},
183+
})
184+
factory.Start(stop)
117185
}
118186

119187
func (env *Environment) AfterEach() {
@@ -137,6 +205,7 @@ func (env *Environment) AfterEach() {
137205
wg.Wait()
138206
env.eventuallyExpectScaleDown()
139207
env.expectNoCrashes()
208+
close(stop) // close the pod/node monitor watch channel
140209
env.printControllerLogs(&v1.PodLogOptions{Container: "controller"})
141210
}
142211

‎test/suites/consolidation/suite_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ var _ = AfterEach(func() {
5757
})
5858

5959
var _ = Describe("Consolidation", func() {
60-
It("should consolidate nodes (delete)", func() {
60+
It("should consolidate nodes (delete)", Label(environment.NoWatch), func() {
6161
provider := test.AWSNodeTemplate(v1alpha1.AWSNodeTemplateSpec{AWS: awsv1alpha1.AWS{
6262
SecurityGroupSelector: map[string]string{"karpenter.sh/discovery": env.ClusterName},
6363
SubnetSelector: map[string]string{"karpenter.sh/discovery": env.ClusterName},

‎test/suites/utilization/suite_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ func TestUtilization(t *testing.T) {
4545
var _ = BeforeEach(func() { env.BeforeEach() })
4646
var _ = AfterEach(func() { env.AfterEach() })
4747

48-
var _ = Describe("Utilization", func() {
48+
var _ = Describe("Utilization", Label(environment.NoWatch), func() {
4949
It("should provision one pod per node", func() {
5050
provider := test.AWSNodeTemplate(v1alpha1.AWSNodeTemplateSpec{AWS: awsv1alpha1.AWS{
5151
SecurityGroupSelector: map[string]string{"karpenter.sh/discovery": env.ClusterName},

0 commit comments

Comments
 (0)
Please sign in to comment.