Skip to content

Commit 5c314c2

Browse files
committed
Convert client.List to use functional options
Replaces: List(ctx, ListOptions, list) with: List(ctx, list, ...option) This matches the upcoming functional options signature of client.Delete. To use the previous builder options, use the UseListOptions functional option: lo := &client.ListOptions{} client.List(ctx, list, client.UseListOptions( lo.InNamespace(ns).MatchingLabels(labels) ))
1 parent 2d4d049 commit 5c314c2

File tree

3 files changed

+234
-83
lines changed

3 files changed

+234
-83
lines changed

pkg/client/client.go

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -137,20 +137,19 @@ func (c *client) Get(ctx context.Context, key ObjectKey, obj runtime.Object) err
137137
}
138138

139139
// List implements client.Client
140-
func (c *client) List(ctx context.Context, opts *ListOptions, obj runtime.Object) error {
140+
func (c *client) List(ctx context.Context, obj runtime.Object, opts ...ListOptionFunc) error {
141141
r, err := c.cache.getResource(obj)
142142
if err != nil {
143143
return err
144144
}
145-
namespace := ""
146-
if opts != nil {
147-
namespace = opts.Namespace
148-
}
145+
146+
listOpts := ListOptions{}
147+
listOpts.ApplyOptions(opts)
149148
return r.Get().
150-
NamespaceIfScoped(namespace, r.isNamespaced()).
149+
NamespaceIfScoped(listOpts.Namespace, r.isNamespaced()).
151150
Resource(r.resource()).
152151
Body(obj).
153-
VersionedParams(opts.AsListOptions(), c.paramCodec).
152+
VersionedParams(listOpts.AsListOptions(), c.paramCodec).
154153
Do().
155154
Into(obj)
156155
}

pkg/client/client_test.go

Lines changed: 178 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -763,7 +763,7 @@ var _ = Describe("Client", func() {
763763

764764
By("listing all objects of that type in the cluster")
765765
deps := &appsv1.DeploymentList{}
766-
Expect(cl.List(context.Background(), nil, deps)).NotTo(HaveOccurred())
766+
Expect(cl.List(context.Background(), deps)).NotTo(HaveOccurred())
767767

768768
Expect(deps.Items).NotTo(BeEmpty())
769769
hasDep := false
@@ -784,7 +784,7 @@ var _ = Describe("Client", func() {
784784

785785
By("listing all Deployments in the cluster")
786786
deps := &appsv1.DeploymentList{}
787-
Expect(cl.List(context.Background(), nil, deps)).NotTo(HaveOccurred())
787+
Expect(cl.List(context.Background(), deps)).NotTo(HaveOccurred())
788788

789789
By("validating no Deployments are returned")
790790
Expect(deps.Items).To(BeEmpty())
@@ -793,59 +793,69 @@ var _ = Describe("Client", func() {
793793
}, serverSideTimeoutSeconds)
794794

795795
// TODO(seans): get label selector test working
796-
// It("should filter results by label selector", func(done Done) {
797-
// By("creating a Deployment with the app=frontend label")
798-
// depFrontend := &appsv1.Deployment{
799-
// ObjectMeta: metav1.ObjectMeta{Name: "deployment-frontend", Namespace: ns},
800-
// Spec: appsv1.DeploymentSpec{
801-
// Selector: &metav1.LabelSelector{
802-
// MatchLabels: map[string]string{"app": "frontend"},
803-
// },
804-
// Template: corev1.PodTemplateSpec{
805-
// ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "frontend"}},
806-
// Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
807-
// },
808-
// },
809-
// }
810-
// depFrontend, err := clientset.AppsV1().Deployments(ns).Create(depFrontend)
811-
// Expect(err).NotTo(HaveOccurred())
812-
813-
// By("creating a Deployment with the app=backend label")
814-
// depBackend := &appsv1.Deployment{
815-
// ObjectMeta: metav1.ObjectMeta{Name: "deployment-backend", Namespace: ns},
816-
// Spec: appsv1.DeploymentSpec{
817-
// Selector: &metav1.LabelSelector{
818-
// MatchLabels: map[string]string{"app": "backend"},
819-
// },
820-
// Template: corev1.PodTemplateSpec{
821-
// ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "backend"}},
822-
// Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
823-
// },
824-
// },
825-
// }
826-
// depBackend, err = clientset.AppsV1().Deployments(ns).Create(depBackend)
827-
// Expect(err).NotTo(HaveOccurred())
828-
829-
// cl, err := client.New(cfg, client.Options{})
830-
// Expect(err).NotTo(HaveOccurred())
831-
832-
// By("listing all Deployments with label app=backend")
833-
// deps := &appsv1.DeploymentList{}
834-
// labels := map[string]string{"app": "backend"}
835-
// lo := client.InNamespace(ns).MatchingLabels(labels)
836-
// Expect(cl.List(context.Background(), lo, deps)).NotTo(HaveOccurred())
837-
838-
// By("only the Deployment with the backend label is returned")
839-
// Expect(deps.Items).NotTo(BeEmpty())
840-
// Expect(1).To(Equal(len(deps.Items)))
841-
// actual := deps.Items[0]
842-
// Expect(actual.Name).To(Equal("deployment-backend"))
843-
844-
// deleteDeployment(depFrontend, ns)
845-
// deleteDeployment(depBackend, ns)
846-
847-
// close(done)
848-
// }, serverSideTimeoutSeconds)
796+
It("should filter results by label selector", func(done Done) {
797+
By("creating a Deployment with the app=frontend label")
798+
depFrontend := &appsv1.Deployment{
799+
ObjectMeta: metav1.ObjectMeta{
800+
Name: "deployment-frontend",
801+
Namespace: ns,
802+
Labels: map[string]string{"app": "frontend"},
803+
},
804+
Spec: appsv1.DeploymentSpec{
805+
Selector: &metav1.LabelSelector{
806+
MatchLabels: map[string]string{"app": "frontend"},
807+
},
808+
Template: corev1.PodTemplateSpec{
809+
ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "frontend"}},
810+
Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
811+
},
812+
},
813+
}
814+
depFrontend, err := clientset.AppsV1().Deployments(ns).Create(depFrontend)
815+
Expect(err).NotTo(HaveOccurred())
816+
817+
By("creating a Deployment with the app=backend label")
818+
depBackend := &appsv1.Deployment{
819+
ObjectMeta: metav1.ObjectMeta{
820+
Name: "deployment-backend",
821+
Namespace: ns,
822+
Labels: map[string]string{"app": "backend"},
823+
},
824+
Spec: appsv1.DeploymentSpec{
825+
Selector: &metav1.LabelSelector{
826+
MatchLabels: map[string]string{"app": "backend"},
827+
},
828+
Template: corev1.PodTemplateSpec{
829+
ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "backend"}},
830+
Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
831+
},
832+
},
833+
}
834+
depBackend, err = clientset.AppsV1().Deployments(ns).Create(depBackend)
835+
Expect(err).NotTo(HaveOccurred())
836+
837+
cl, err := client.New(cfg, client.Options{})
838+
Expect(err).NotTo(HaveOccurred())
839+
840+
By("listing all Deployments with label app=backend")
841+
deps := &appsv1.DeploymentList{}
842+
labels := map[string]string{"app": "backend"}
843+
err = cl.List(context.Background(), deps,
844+
client.MatchingLabels(labels),
845+
)
846+
Expect(err).NotTo(HaveOccurred())
847+
848+
By("only the Deployment with the backend label is returned")
849+
Expect(deps.Items).NotTo(BeEmpty())
850+
Expect(1).To(Equal(len(deps.Items)))
851+
actual := deps.Items[0]
852+
Expect(actual.Name).To(Equal("deployment-backend"))
853+
854+
deleteDeployment(depFrontend, ns)
855+
deleteDeployment(depBackend, ns)
856+
857+
close(done)
858+
}, serverSideTimeoutSeconds)
849859

850860
It("should filter results by namespace selector", func(done Done) {
851861
By("creating a Deployment in test-namespace-1")
@@ -891,8 +901,8 @@ var _ = Describe("Client", func() {
891901

892902
By("listing all Deployments in test-namespace-1")
893903
deps := &appsv1.DeploymentList{}
894-
lo := client.InNamespace("test-namespace-1")
895-
Expect(cl.List(context.Background(), lo, deps)).NotTo(HaveOccurred())
904+
err = cl.List(context.Background(), deps, client.InNamespace("test-namespace-1"))
905+
Expect(err).NotTo(HaveOccurred())
896906

897907
By("only the Deployment in test-namespace-1 is returned")
898908
Expect(deps.Items).NotTo(BeEmpty())
@@ -946,8 +956,8 @@ var _ = Describe("Client", func() {
946956

947957
By("listing all Deployments with field metadata.name=deployment-backend")
948958
deps := &appsv1.DeploymentList{}
949-
lo := client.MatchingField("metadata.name", "deployment-backend")
950-
Expect(cl.List(context.Background(), lo, deps)).NotTo(HaveOccurred())
959+
err = cl.List(context.Background(), deps, client.MatchingField("metadata.name", "deployment-backend"))
960+
Expect(err).NotTo(HaveOccurred())
951961

952962
By("only the Deployment with the backend field is returned")
953963
Expect(deps.Items).NotTo(BeEmpty())
@@ -961,6 +971,101 @@ var _ = Describe("Client", func() {
961971
close(done)
962972
}, serverSideTimeoutSeconds)
963973

974+
It("should filter results by namespace selector and label selector", func(done Done) {
975+
By("creating a Deployment in test-namespace-3 with the app=frontend label")
976+
tns3 := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "test-namespace-3"}}
977+
_, err := clientset.CoreV1().Namespaces().Create(tns3)
978+
Expect(err).NotTo(HaveOccurred())
979+
depFrontend3 := &appsv1.Deployment{
980+
ObjectMeta: metav1.ObjectMeta{
981+
Name: "deployment-frontend",
982+
Namespace: "test-namespace-3",
983+
Labels: map[string]string{"app": "frontend"},
984+
},
985+
Spec: appsv1.DeploymentSpec{
986+
Selector: &metav1.LabelSelector{
987+
MatchLabels: map[string]string{"app": "frontend"},
988+
},
989+
Template: corev1.PodTemplateSpec{
990+
ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "frontend"}},
991+
Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
992+
},
993+
},
994+
}
995+
depFrontend3, err = clientset.AppsV1().Deployments("test-namespace-3").Create(depFrontend3)
996+
Expect(err).NotTo(HaveOccurred())
997+
998+
By("creating a Deployment in test-namespace-3 with the app=backend label")
999+
depBackend3 := &appsv1.Deployment{
1000+
ObjectMeta: metav1.ObjectMeta{
1001+
Name: "deployment-backend",
1002+
Namespace: "test-namespace-3",
1003+
Labels: map[string]string{"app": "backend"},
1004+
},
1005+
Spec: appsv1.DeploymentSpec{
1006+
Selector: &metav1.LabelSelector{
1007+
MatchLabels: map[string]string{"app": "backend"},
1008+
},
1009+
Template: corev1.PodTemplateSpec{
1010+
ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "backend"}},
1011+
Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
1012+
},
1013+
},
1014+
}
1015+
depBackend3, err = clientset.AppsV1().Deployments("test-namespace-3").Create(depBackend3)
1016+
Expect(err).NotTo(HaveOccurred())
1017+
1018+
By("creating a Deployment in test-namespace-4 with the app=frontend label")
1019+
tns4 := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "test-namespace-4"}}
1020+
_, err = clientset.CoreV1().Namespaces().Create(tns4)
1021+
Expect(err).NotTo(HaveOccurred())
1022+
depFrontend4 := &appsv1.Deployment{
1023+
ObjectMeta: metav1.ObjectMeta{
1024+
Name: "deployment-frontend",
1025+
Namespace: "test-namespace-4",
1026+
Labels: map[string]string{"app": "frontend"},
1027+
},
1028+
Spec: appsv1.DeploymentSpec{
1029+
Selector: &metav1.LabelSelector{
1030+
MatchLabels: map[string]string{"app": "frontend"},
1031+
},
1032+
Template: corev1.PodTemplateSpec{
1033+
ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "frontend"}},
1034+
Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
1035+
},
1036+
},
1037+
}
1038+
depFrontend4, err = clientset.AppsV1().Deployments("test-namespace-4").Create(depFrontend4)
1039+
Expect(err).NotTo(HaveOccurred())
1040+
1041+
cl, err := client.New(cfg, client.Options{})
1042+
Expect(err).NotTo(HaveOccurred())
1043+
1044+
By("listing all Deployments in test-namespace-3 with label app=frontend")
1045+
deps := &appsv1.DeploymentList{}
1046+
labels := map[string]string{"app": "frontend"}
1047+
err = cl.List(context.Background(), deps,
1048+
client.InNamespace("test-namespace-3"),
1049+
client.MatchingLabels(labels),
1050+
)
1051+
Expect(err).NotTo(HaveOccurred())
1052+
1053+
By("only the Deployment in test-namespace-3 with label app=frontend is returned")
1054+
Expect(deps.Items).NotTo(BeEmpty())
1055+
Expect(1).To(Equal(len(deps.Items)))
1056+
actual := deps.Items[0]
1057+
Expect(actual.Name).To(Equal("deployment-frontend"))
1058+
Expect(actual.Namespace).To(Equal("test-namespace-3"))
1059+
1060+
deleteDeployment(depFrontend3, "test-namespace-3")
1061+
deleteDeployment(depBackend3, "test-namespace-3")
1062+
deleteDeployment(depFrontend4, "test-namespace-4")
1063+
deleteNamespace(tns3)
1064+
deleteNamespace(tns4)
1065+
1066+
close(done)
1067+
}, serverSideTimeoutSeconds)
1068+
9641069
PIt("should fail if it cannot get a client", func() {
9651070

9661071
})
@@ -1028,19 +1133,30 @@ var _ = Describe("Client", func() {
10281133

10291134
It("should be created from MatchingLabels", func() {
10301135
labels := map[string]string{"foo": "bar"}
1031-
lo := client.MatchingLabels(labels)
1136+
lo := &client.ListOptions{}
1137+
client.MatchingLabels(labels)(lo)
10321138
Expect(lo).NotTo(BeNil())
10331139
Expect(lo.LabelSelector.String()).To(Equal("foo=bar"))
10341140
})
10351141

10361142
It("should be created from MatchingField", func() {
1037-
lo := client.MatchingField("field1", "bar")
1143+
lo := &client.ListOptions{}
1144+
client.MatchingField("field1", "bar")(lo)
10381145
Expect(lo).NotTo(BeNil())
10391146
Expect(lo.FieldSelector.String()).To(Equal("field1=bar"))
10401147
})
10411148

10421149
It("should be created from InNamespace", func() {
1043-
lo := client.InNamespace("test")
1150+
lo := &client.ListOptions{}
1151+
client.InNamespace("test")(lo)
1152+
Expect(lo).NotTo(BeNil())
1153+
Expect(lo.Namespace).To(Equal("test"))
1154+
})
1155+
1156+
It("should allow pre-built ListOptions", func() {
1157+
lo := &client.ListOptions{}
1158+
newLo := &client.ListOptions{}
1159+
client.UseListOptions(newLo.InNamespace("test"))(lo)
10441160
Expect(lo).NotTo(BeNil())
10451161
Expect(lo.Namespace).To(Equal("test"))
10461162
})

0 commit comments

Comments
 (0)