Kubernetes Go客户端测试时通过spec.nodeName的FieldSelector过滤Pod失效
问题原因
- k8s官方提供的
client-go/fake客户端默认仅支持metadata相关字段的FieldSelector筛选,比如metadata.name、metadata.namespace这类字段。 - 针对
spec.nodeName、status.phase等非metadata字段,fake客户端没有内置对应的筛选逻辑,会直接忽略传入的FieldSelector参数,返回全部匹配资源类型的对象,这是设计上的特性而非bug,不需要提交issue。
解决方法
你可以通过给fake客户端添加自定义Reactor,手动实现spec.nodeName字段的筛选逻辑,示例代码如下:
func TestListRunningPodsByNodeName(t *testing.T) { // 构造测试用Pod数据 pod1 := &v1.Pod{ ObjectMeta: metav1.ObjectMeta{ Name: "pod1", Namespace: "default", }, Spec: v1.PodSpec{ NodeName: "foo", }, } pod2 := &v1.Pod{ ObjectMeta: metav1.ObjectMeta{ Name: "pod2", Namespace: "default", }, Spec: v1.PodSpec{ NodeName: "bar", }, } kubeClient := fake.NewSimpleClientset(pod1, pod2) // 自定义Reactor处理spec.nodeName的FieldSelector筛选 kubeClient.PrependReactor("list", "pods", func(action clienttesting.Action) (handled bool, ret runtime.Object, err error) { listAction := action.(clienttesting.ListAction) fieldSelector := listAction.GetListRestrictions().Fields if fieldSelector.Empty() { return false, nil, nil } // 匹配spec.nodeName的筛选规则 nodeName, ok := fieldSelector.RequiresExactMatch("spec.nodeName") if !ok { return false, nil, nil } // 手动过滤符合条件的Pod filtered := &v1.PodList{} for _, pod := range []*v1.Pod{pod1, pod2} { if pod.Spec.NodeName == nodeName { filtered.Items = append(filtered.Items, *pod) } } return true, filtered, nil }) // 调用方法验证 got, err := ListRunningPodsByNodeName(kubeClient, "foo") if err != nil { t.Fatalf("unexpected error: %v", err) } if len(got.Items) != 1 || got.Items[0].Name != "pod1" { t.Errorf("expected 1 pod named pod1, got %d pods", len(got.Items)) } }
如果不想自定义Reactor,也可以在测试逻辑里,拿到返回的PodList后手动按spec.nodeName过滤校验,适合临时测试的场景。
内容的提问来源于stack exchange,提问作者Borja Tur
相关产品推荐
相关产品推荐

