Way of filter Pods by FieldSelector spec.nodeName when testing kubernetes go client api calls

huangapple go评论100阅读模式
英文:

Way of filter Pods by FieldSelector spec.nodeName when testing kubernetes go client api calls

问题

作为编写在给定 k8s 节点中列出 pod 的逻辑的一部分,我有以下的 API 调用:

func ListRunningPodsByNodeName(kubeClient kubernetes.Interface, nodeName string) (*v1.PodList, error) {
    return kubeClient.
        CoreV1().
        Pods("").
        List(context.TODO(), metav1.ListOptions{
            FieldSelector: "spec.nodeName=" + nodeName,
        })
}

为了使用 k8s 提供的 fake client 来测试 ListRunningPodsByNodeName,我提供了以下的测试初始化代码:

func TestListRunningPodsByNodeName(t *testing.T) {

    // happy path
    kubeClient := fake.NewSimpleClientset(&v1.Pod{
        ObjectMeta: metav1.ObjectMeta{
            Name:        "pod1",
            Namespace:   "default",
            Annotations: map[string]string{},
        },
        Spec: v1.PodSpec{
            NodeName: "foo",
        },
    }, &v1.Pod{
        ObjectMeta: metav1.ObjectMeta{
            Name:        "pod2",
            Namespace:   "default",
            Annotations: map[string]string{},
        },
        Spec: v1.PodSpec{
            NodeName: "bar",
        },
    })

    got, _ := ListRunningPodsByNodeName(kubeClient, "foo")

    for i, pod := range got.Items {
        fmt.Println(fmt.Sprintf("[%2d] %s", i, pod.GetName()))
    }

    t.Errorf("Error, expecting only one pod")
}

在调试时,我发现返回了 pod1pod2 的 Pod,尽管我正在通过过滤器只获取在 foo 节点上运行的 Pod。对于使用相同方法按特定元数据进行过滤,这种方法运行得很好,但是在按 nodeName 进行过滤时无法正常工作。有人知道原因吗?我怀疑这可能是 fake client 的能力限制,但还不确定是否应该提出问题。

提前感谢。

英文:

As part of writing logic for listing pods within a give k8s node I've the following api call:

func ListRunningPodsByNodeName(kubeClient kubernetes.Interface, nodeName string (*v1.PodList, error) {
  return kubeClient.
	CoreV1().
	Pods("").
    List(context.TODO(), metav1.ListOptions{
        FieldSelector: "spec.nodeName=" + nodeName,
    })
}

In order to test ListRunningPodsByNodeName using the fake client provided by k8s, I came up with the following test initialization:

func TestListRunningPodsByNodeName(t *testing.T) {

	// happy path
	kubeClient := fake.NewSimpleClientset(&v1.Pod{
    ObjectMeta: metav1.ObjectMeta{
        Name:        "pod1",
        Namespace:   "default",
        Annotations: map[string]string{},
    },
		Spec: v1.PodSpec{
			NodeName: "foo",
		},
	}, &v1.Pod{
			ObjectMeta: metav1.ObjectMeta{
					Name:        "pod2",
					Namespace:   "default",
					Annotations: map[string]string{},
			},
			Spec: v1.PodSpec{
				NodeName: "bar",
			},
	})

	got, _ := ListRunningPodsByNodeName(kubeClient, "foo")

	for i, pod := range got.Items {
		fmt.Println(fmt.Sprintf("[%2d] %s", i, pod.GetName()))
	}

	t.Errorf("Error, expecting only one pod")
}

When debugging, I got pod1 and pod2 Pods returned despite I'm filtering by those running within foo node. Using this same approach for filtering by certain metadata work like a charm but can't make this to work in case of filtering by nodeName. ¿Anyone knows why please? I suspect it might be a limitation with the fake client capabilities but not completely sure to open an issue yet

thanks by advance

答案1

得分: 2

假的 k8s 客户端不支持通过字段选择器进行过滤(参见此评论)。在使用假的 k8s 客户端进行单元测试时,最好假设 k8s 客户端会按预期工作(根据字段选择器查询返回正确的 pod)。在你的测试中,提供给假的 k8s 客户端的 pod 应该符合你的应用程序的预期,并测试你自己的逻辑,而不是同时测试 k8s 客户端的查询逻辑。

如果假客户端必须为你执行过滤操作,你可以尝试使用假客户端反应器(reactors)将这个自定义行为注入到假客户端中。这只是意味着需要更多的样板代码。

> 任何非通用的行为(如字段选择行为)都可以通过添加处理特定类型操作的反应器来在测试中注入,使用操作中的附加信息(在这种情况下,ListAction#GetListRestrictions().Fields),并自定义返回的数据。

我没有进行过任何测试,但希望这能给你一个起点。

client := fake.NewSimpleClientset()
client.AddReactor("*", "MyResource", func(action testing.Action) (handled bool, ret runtime.Object, err error) {
    // 在这里添加自定义的过滤逻辑
})
英文:

The fake k8s client does not support filtering by field selector (see this comment). When unit testing with the fake k8s client, it's best to assume that the k8s client will work as expected in the real world (return the correct pods based on your field selector query). In your test, provide the pods to the fake k8s client that your application expects and test your own logic, rather than also testing the query logic of the k8s client.

If it's absolutely critical that the fake client perform the filtering for you, you may be able to use the fake client reactors to inject this custom behavior into the fake client. It just means more boilerplate code.

> Anything non-generic (like field selection behavior) can be injected in your tests by adding reactors that deal with specific types of actions, use additional info in the action (in this case, ListAction#GetListRestrictions().Fields), and customize the data returned

I haven't tested this at all but hopefully it gives you something to start with.

client := fake.NewSimpleClientset()
client.AddReactor("*", "MyResource", func(action testing.Action) (handled bool, ret runtime.Object, err error) {
	// Add custom filtering logic here
})

huangapple
  • 本文由 发表于 2021年6月3日 19:48:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/67820929.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定