Skip to content

Commit f969025

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 3aaf8cd commit f969025

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
@@ -648,7 +648,7 @@ var _ = Describe("Client", func() {
648648

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

653653
Expect(deps.Items).NotTo(BeEmpty())
654654
hasDep := false
@@ -669,7 +669,7 @@ var _ = Describe("Client", func() {
669669

670670
By("listing all Deployments in the cluster")
671671
deps := &appsv1.DeploymentList{}
672-
Expect(cl.List(context.Background(), nil, deps)).NotTo(HaveOccurred())
672+
Expect(cl.List(context.Background(), deps)).NotTo(HaveOccurred())
673673

674674
By("validating no Deployments are returned")
675675
Expect(deps.Items).To(BeEmpty())
@@ -678,59 +678,69 @@ var _ = Describe("Client", func() {
678678
}, serverSideTimeoutSeconds)
679679

680680
// TODO(seans): get label selector test working
681-
// It("should filter results by label selector", func(done Done) {
682-
// By("creating a Deployment with the app=frontend label")
683-
// depFrontend := &appsv1.Deployment{
684-
// ObjectMeta: metav1.ObjectMeta{Name: "deployment-frontend", Namespace: ns},
685-
// Spec: appsv1.DeploymentSpec{
686-
// Selector: &metav1.LabelSelector{
687-
// MatchLabels: map[string]string{"app": "frontend"},
688-
// },
689-
// Template: corev1.PodTemplateSpec{
690-
// ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "frontend"}},
691-
// Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
692-
// },
693-
// },
694-
// }
695-
// depFrontend, err := clientset.AppsV1().Deployments(ns).Create(depFrontend)
696-
// Expect(err).NotTo(HaveOccurred())
697-
698-
// By("creating a Deployment with the app=backend label")
699-
// depBackend := &appsv1.Deployment{
700-
// ObjectMeta: metav1.ObjectMeta{Name: "deployment-backend", Namespace: ns},
701-
// Spec: appsv1.DeploymentSpec{
702-
// Selector: &metav1.LabelSelector{
703-
// MatchLabels: map[string]string{"app": "backend"},
704-
// },
705-
// Template: corev1.PodTemplateSpec{
706-
// ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "backend"}},
707-
// Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
708-
// },
709-
// },
710-
// }
711-
// depBackend, err = clientset.AppsV1().Deployments(ns).Create(depBackend)
712-
// Expect(err).NotTo(HaveOccurred())
713-
714-
// cl, err := client.New(cfg, client.Options{})
715-
// Expect(err).NotTo(HaveOccurred())
716-
717-
// By("listing all Deployments with label app=backend")
718-
// deps := &appsv1.DeploymentList{}
719-
// labels := map[string]string{"app": "backend"}
720-
// lo := client.InNamespace(ns).MatchingLabels(labels)
721-
// Expect(cl.List(context.Background(), lo, deps)).NotTo(HaveOccurred())
722-
723-
// By("only the Deployment with the backend label is returned")
724-
// Expect(deps.Items).NotTo(BeEmpty())
725-
// Expect(1).To(Equal(len(deps.Items)))
726-
// actual := deps.Items[0]
727-
// Expect(actual.Name).To(Equal("deployment-backend"))
728-
729-
// deleteDeployment(depFrontend, ns)
730-
// deleteDeployment(depBackend, ns)
731-
732-
// close(done)
733-
// }, serverSideTimeoutSeconds)
681+
It("should filter results by label selector", func(done Done) {
682+
By("creating a Deployment with the app=frontend label")
683+
depFrontend := &appsv1.Deployment{
684+
ObjectMeta: metav1.ObjectMeta{
685+
Name: "deployment-frontend",
686+
Namespace: ns,
687+
Labels: map[string]string{"app": "frontend"},
688+
},
689+
Spec: appsv1.DeploymentSpec{
690+
Selector: &metav1.LabelSelector{
691+
MatchLabels: map[string]string{"app": "frontend"},
692+
},
693+
Template: corev1.PodTemplateSpec{
694+
ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "frontend"}},
695+
Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
696+
},
697+
},
698+
}
699+
depFrontend, err := clientset.AppsV1().Deployments(ns).Create(depFrontend)
700+
Expect(err).NotTo(HaveOccurred())
701+
702+
By("creating a Deployment with the app=backend label")
703+
depBackend := &appsv1.Deployment{
704+
ObjectMeta: metav1.ObjectMeta{
705+
Name: "deployment-backend",
706+
Namespace: ns,
707+
Labels: map[string]string{"app": "backend"},
708+
},
709+
Spec: appsv1.DeploymentSpec{
710+
Selector: &metav1.LabelSelector{
711+
MatchLabels: map[string]string{"app": "backend"},
712+
},
713+
Template: corev1.PodTemplateSpec{
714+
ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "backend"}},
715+
Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
716+
},
717+
},
718+
}
719+
depBackend, err = clientset.AppsV1().Deployments(ns).Create(depBackend)
720+
Expect(err).NotTo(HaveOccurred())
721+
722+
cl, err := client.New(cfg, client.Options{})
723+
Expect(err).NotTo(HaveOccurred())
724+
725+
By("listing all Deployments with label app=backend")
726+
deps := &appsv1.DeploymentList{}
727+
labels := map[string]string{"app": "backend"}
728+
err = cl.List(context.Background(), deps,
729+
client.MatchingLabels(labels),
730+
)
731+
Expect(err).NotTo(HaveOccurred())
732+
733+
By("only the Deployment with the backend label is returned")
734+
Expect(deps.Items).NotTo(BeEmpty())
735+
Expect(1).To(Equal(len(deps.Items)))
736+
actual := deps.Items[0]
737+
Expect(actual.Name).To(Equal("deployment-backend"))
738+
739+
deleteDeployment(depFrontend, ns)
740+
deleteDeployment(depBackend, ns)
741+
742+
close(done)
743+
}, serverSideTimeoutSeconds)
734744

735745
It("should filter results by namespace selector", func(done Done) {
736746
By("creating a Deployment in test-namespace-1")
@@ -776,8 +786,8 @@ var _ = Describe("Client", func() {
776786

777787
By("listing all Deployments in test-namespace-1")
778788
deps := &appsv1.DeploymentList{}
779-
lo := client.InNamespace("test-namespace-1")
780-
Expect(cl.List(context.Background(), lo, deps)).NotTo(HaveOccurred())
789+
err = cl.List(context.Background(), deps, client.InNamespace("test-namespace-1"))
790+
Expect(err).NotTo(HaveOccurred())
781791

782792
By("only the Deployment in test-namespace-1 is returned")
783793
Expect(deps.Items).NotTo(BeEmpty())
@@ -831,8 +841,8 @@ var _ = Describe("Client", func() {
831841

832842
By("listing all Deployments with field metadata.name=deployment-backend")
833843
deps := &appsv1.DeploymentList{}
834-
lo := client.MatchingField("metadata.name", "deployment-backend")
835-
Expect(cl.List(context.Background(), lo, deps)).NotTo(HaveOccurred())
844+
err = cl.List(context.Background(), deps, client.MatchingField("metadata.name", "deployment-backend"))
845+
Expect(err).NotTo(HaveOccurred())
836846

837847
By("only the Deployment with the backend field is returned")
838848
Expect(deps.Items).NotTo(BeEmpty())
@@ -846,6 +856,101 @@ var _ = Describe("Client", func() {
846856
close(done)
847857
}, serverSideTimeoutSeconds)
848858

859+
It("should filter results by namespace selector and label selector", func(done Done) {
860+
By("creating a Deployment in test-namespace-3 with the app=frontend label")
861+
tns3 := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "test-namespace-3"}}
862+
_, err := clientset.CoreV1().Namespaces().Create(tns3)
863+
Expect(err).NotTo(HaveOccurred())
864+
depFrontend3 := &appsv1.Deployment{
865+
ObjectMeta: metav1.ObjectMeta{
866+
Name: "deployment-frontend",
867+
Namespace: "test-namespace-3",
868+
Labels: map[string]string{"app": "frontend"},
869+
},
870+
Spec: appsv1.DeploymentSpec{
871+
Selector: &metav1.LabelSelector{
872+
MatchLabels: map[string]string{"app": "frontend"},
873+
},
874+
Template: corev1.PodTemplateSpec{
875+
ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "frontend"}},
876+
Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
877+
},
878+
},
879+
}
880+
depFrontend3, err = clientset.AppsV1().Deployments("test-namespace-3").Create(depFrontend3)
881+
Expect(err).NotTo(HaveOccurred())
882+
883+
By("creating a Deployment in test-namespace-3 with the app=backend label")
884+
depBackend3 := &appsv1.Deployment{
885+
ObjectMeta: metav1.ObjectMeta{
886+
Name: "deployment-backend",
887+
Namespace: "test-namespace-3",
888+
Labels: map[string]string{"app": "backend"},
889+
},
890+
Spec: appsv1.DeploymentSpec{
891+
Selector: &metav1.LabelSelector{
892+
MatchLabels: map[string]string{"app": "backend"},
893+
},
894+
Template: corev1.PodTemplateSpec{
895+
ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "backend"}},
896+
Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
897+
},
898+
},
899+
}
900+
depBackend3, err = clientset.AppsV1().Deployments("test-namespace-3").Create(depBackend3)
901+
Expect(err).NotTo(HaveOccurred())
902+
903+
By("creating a Deployment in test-namespace-4 with the app=frontend label")
904+
tns4 := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "test-namespace-4"}}
905+
_, err = clientset.CoreV1().Namespaces().Create(tns4)
906+
Expect(err).NotTo(HaveOccurred())
907+
depFrontend4 := &appsv1.Deployment{
908+
ObjectMeta: metav1.ObjectMeta{
909+
Name: "deployment-frontend",
910+
Namespace: "test-namespace-4",
911+
Labels: map[string]string{"app": "frontend"},
912+
},
913+
Spec: appsv1.DeploymentSpec{
914+
Selector: &metav1.LabelSelector{
915+
MatchLabels: map[string]string{"app": "frontend"},
916+
},
917+
Template: corev1.PodTemplateSpec{
918+
ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "frontend"}},
919+
Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
920+
},
921+
},
922+
}
923+
depFrontend4, err = clientset.AppsV1().Deployments("test-namespace-4").Create(depFrontend4)
924+
Expect(err).NotTo(HaveOccurred())
925+
926+
cl, err := client.New(cfg, client.Options{})
927+
Expect(err).NotTo(HaveOccurred())
928+
929+
By("listing all Deployments in test-namespace-3 with label app=frontend")
930+
deps := &appsv1.DeploymentList{}
931+
labels := map[string]string{"app": "frontend"}
932+
err = cl.List(context.Background(), deps,
933+
client.InNamespace("test-namespace-3"),
934+
client.MatchingLabels(labels),
935+
)
936+
Expect(err).NotTo(HaveOccurred())
937+
938+
By("only the Deployment in test-namespace-3 with label app=frontend is returned")
939+
Expect(deps.Items).NotTo(BeEmpty())
940+
Expect(1).To(Equal(len(deps.Items)))
941+
actual := deps.Items[0]
942+
Expect(actual.Name).To(Equal("deployment-frontend"))
943+
Expect(actual.Namespace).To(Equal("test-namespace-3"))
944+
945+
deleteDeployment(depFrontend3, "test-namespace-3")
946+
deleteDeployment(depBackend3, "test-namespace-3")
947+
deleteDeployment(depFrontend4, "test-namespace-4")
948+
deleteNamespace(tns3)
949+
deleteNamespace(tns4)
950+
951+
close(done)
952+
}, serverSideTimeoutSeconds)
953+
849954
It("should fail if it cannot get a client", func() {
850955

851956
})
@@ -913,19 +1018,30 @@ var _ = Describe("Client", func() {
9131018

9141019
It("should be created from MatchingLabels", func() {
9151020
labels := map[string]string{"foo": "bar"}
916-
lo := client.MatchingLabels(labels)
1021+
lo := &client.ListOptions{}
1022+
client.MatchingLabels(labels)(lo)
9171023
Expect(lo).NotTo(BeNil())
9181024
Expect(lo.LabelSelector.String()).To(Equal("foo=bar"))
9191025
})
9201026

9211027
It("should be created from MatchingField", func() {
922-
lo := client.MatchingField("field1", "bar")
1028+
lo := &client.ListOptions{}
1029+
client.MatchingField("field1", "bar")(lo)
9231030
Expect(lo).NotTo(BeNil())
9241031
Expect(lo.FieldSelector.String()).To(Equal("field1=bar"))
9251032
})
9261033

9271034
It("should be created from InNamespace", func() {
928-
lo := client.InNamespace("test")
1035+
lo := &client.ListOptions{}
1036+
client.InNamespace("test")(lo)
1037+
Expect(lo).NotTo(BeNil())
1038+
Expect(lo.Namespace).To(Equal("test"))
1039+
})
1040+
1041+
It("should allow pre-built ListOptions", func() {
1042+
lo := &client.ListOptions{}
1043+
newLo := &client.ListOptions{}
1044+
client.UseListOptions(newLo.InNamespace("test"))(lo)
9291045
Expect(lo).NotTo(BeNil())
9301046
Expect(lo.Namespace).To(Equal("test"))
9311047
})

0 commit comments

Comments
 (0)