Refactor PodsServer to use PodManager as source of truth

- Fixed version in kube_features.go after rebase (1.35->1.36)
- Removed internal pod cache in PodsServer to reduce memory footprint and avoid duplication.
- Injected pod.Manager into PodsServer to serve as the single source of truth for pod data.
- Refactored WatchPods to broadcast UIDs and fetch fresh pod data from podManager, ensuring consistency.
- Updated convertWatchEventType to safely handle unknown event types.
- Refactored unit tests to use MockManager and added a test case for static pods.
- Updated e2e suite with static pod test
This commit is contained in:
Brian Sonnenberg
2025-12-16 20:29:55 +00:00
parent 044f65ca5c
commit fd330c303d
5 changed files with 208 additions and 89 deletions

View File

@@ -20,6 +20,9 @@ package e2enode
import (
"context"
"encoding/json"
"os"
"path/filepath"
"time"
"github.com/onsi/ginkgo/v2"
@@ -39,6 +42,7 @@ import (
"k8s.io/kubernetes/test/e2e/framework"
e2epod "k8s.io/kubernetes/test/e2e/framework/pod"
admissionapi "k8s.io/pod-security-admission/api"
"sigs.k8s.io/yaml"
)
// podsAPISuite is a Ginkgo test suite for the Kubelet Pods API.
@@ -195,5 +199,93 @@ var _ = SIGDescribe("Kubelet Pods API", framework.WithSerial(), func() {
)), "did not receive DELETED event for the test pod")
})
ginkgo.It("should be able to list and watch static pods", func(ctx context.Context) {
ginkgo.By("watching for pod events")
watchCtx, cancel := context.WithTimeout(ctx, 5*time.Minute)
defer cancel()
watchClient, err := client.WatchPods(watchCtx, &podsv1alpha1.WatchPodsRequest{})
framework.ExpectNoError(err, "failed to watch pods")
eventsCh := make(chan *podsv1alpha1.WatchPodsEvent, 100)
go func() {
defer ginkgo.GinkgoRecover()
for {
ev, err := watchClient.Recv()
if err != nil {
return
}
select {
case eventsCh <- ev:
case <-watchCtx.Done():
return
}
}
}()
ginkgo.By("creating a static pod manifest")
staticPodName := "static-pod-" + string(uuid.NewUUID())
staticPodPath := filepath.Join(kubeletCfg.StaticPodPath, f.Namespace.Name+"-"+staticPodName+".yaml")
pod := &v1.Pod{
TypeMeta: metav1.TypeMeta{
Kind: "Pod",
APIVersion: "v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: staticPodName,
Namespace: f.Namespace.Name,
},
Spec: v1.PodSpec{
Containers: []v1.Container{
{
Name: "test-container",
Image: "busybox:1.36",
Command: []string{"sleep", "3600"},
},
},
},
}
podBytes, err := json.Marshal(pod)
framework.ExpectNoError(err, "failed to marshal pod")
podYaml, err := yaml.JSONToYAML(podBytes)
framework.ExpectNoError(err, "failed to convert to yaml")
err = os.WriteFile(staticPodPath, podYaml, 0644)
framework.ExpectNoError(err, "failed to write static pod file")
defer func() {
os.Remove(staticPodPath)
}()
ginkgo.By("waiting for the static pod ADDED event")
gomega.Eventually(eventsCh, "2m").Should(gomega.Receive(gomega.SatisfyAll(
gomega.WithTransform(func(e *podsv1alpha1.WatchPodsEvent) podsv1alpha1.EventType { return e.Type }, gomega.Equal(podsv1alpha1.EventType_ADDED)),
gomega.WithTransform(func(e *podsv1alpha1.WatchPodsEvent) bool {
var p v1.Pod
if err := p.Unmarshal(e.Pod); err != nil {
return false
}
return p.Namespace == f.Namespace.Name && p.Name == staticPodName+"-"+framework.TestContext.NodeName
}, gomega.BeTrue()),
)), "did not receive ADDED event")
ginkgo.By("deleting the static pod manifest")
err = os.Remove(staticPodPath)
framework.ExpectNoError(err, "failed to delete static pod file")
ginkgo.By("waiting for the static pod DELETED event")
gomega.Eventually(eventsCh, "2m").Should(gomega.Receive(gomega.SatisfyAll(
gomega.WithTransform(func(e *podsv1alpha1.WatchPodsEvent) podsv1alpha1.EventType { return e.Type }, gomega.Equal(podsv1alpha1.EventType_DELETED)),
gomega.WithTransform(func(e *podsv1alpha1.WatchPodsEvent) bool {
var p v1.Pod
if err := p.Unmarshal(e.Pod); err != nil {
return false
}
return p.Namespace == f.Namespace.Name && p.Name == staticPodName+"-"+framework.TestContext.NodeName
}, gomega.BeTrue()),
)), "did not receive DELETED event")
})
})
})