Skip to content

Commit 3465711

Browse files
committed
Enable labels list options in fake client
This commit allows passing label matches to the fake client List() function. This is done in a way similar to the CachedReader. Both now share a common call to `listutil.FilterWithLabels`. Signed-off-by: sebgl <[email protected]>
1 parent 6ada5f3 commit 3465711

File tree

4 files changed

+98
-27
lines changed

4 files changed

+98
-27
lines changed

pkg/cache/internal/cache_reader.go

Lines changed: 9 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929
"k8s.io/apimachinery/pkg/runtime/schema"
3030
"k8s.io/apimachinery/pkg/selection"
3131
"k8s.io/client-go/tools/cache"
32+
"sigs.k8s.io/controller-runtime/pkg/cache/listutil"
3233
"sigs.k8s.io/controller-runtime/pkg/client"
3334
)
3435

@@ -118,33 +119,19 @@ func (c *CacheReader) List(_ context.Context, out runtime.Object, opts ...client
118119
labelSel = listOpts.LabelSelector
119120
}
120121

121-
outItems, err := c.getListItems(objs, labelSel)
122-
if err != nil {
123-
return err
124-
}
125-
return apimeta.SetList(out, outItems)
126-
}
127-
128-
func (c *CacheReader) getListItems(objs []interface{}, labelSel labels.Selector) ([]runtime.Object, error) {
129-
outItems := make([]runtime.Object, 0, len(objs))
122+
runtimeObjs := make([]runtime.Object, 0, len(objs))
130123
for _, item := range objs {
131124
obj, isObj := item.(runtime.Object)
132125
if !isObj {
133-
return nil, fmt.Errorf("cache contained %T, which is not an Object", obj)
126+
return fmt.Errorf("cache contained %T, which is not an Object", obj)
134127
}
135-
meta, err := apimeta.Accessor(obj)
136-
if err != nil {
137-
return nil, err
138-
}
139-
if labelSel != nil {
140-
lbls := labels.Set(meta.GetLabels())
141-
if !labelSel.Matches(lbls) {
142-
continue
143-
}
144-
}
145-
outItems = append(outItems, obj.DeepCopyObject())
128+
runtimeObjs = append(runtimeObjs, obj)
129+
}
130+
filteredItems, err := listutil.FilterWithLabels(runtimeObjs, labelSel)
131+
if err != nil {
132+
return err
146133
}
147-
return outItems, nil
134+
return apimeta.SetList(out, filteredItems)
148135
}
149136

150137
// objectKeyToStorageKey converts an object key to store key.

pkg/cache/listutil/filter.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
Copyright 2018 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package listutil
18+
19+
import (
20+
apimeta "k8s.io/apimachinery/pkg/api/meta"
21+
"k8s.io/apimachinery/pkg/labels"
22+
"k8s.io/apimachinery/pkg/runtime"
23+
)
24+
25+
// FilterWithLabels returns a copy of the items in objs matching labelSel
26+
func FilterWithLabels(objs []runtime.Object, labelSel labels.Selector) ([]runtime.Object, error) {
27+
outItems := make([]runtime.Object, 0, len(objs))
28+
for _, obj := range objs {
29+
meta, err := apimeta.Accessor(obj)
30+
if err != nil {
31+
return nil, err
32+
}
33+
if labelSel != nil {
34+
lbls := labels.Set(meta.GetLabels())
35+
if !labelSel.Matches(lbls) {
36+
continue
37+
}
38+
}
39+
outItems = append(outItems, obj.DeepCopyObject())
40+
}
41+
return outItems, nil
42+
}

pkg/client/fake/client.go

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929
"k8s.io/client-go/kubernetes/scheme"
3030
"k8s.io/client-go/testing"
3131

32+
"sigs.k8s.io/controller-runtime/pkg/cache/listutil"
3233
"sigs.k8s.io/controller-runtime/pkg/client"
3334
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
3435
logf "sigs.k8s.io/controller-runtime/pkg/internal/log"
@@ -114,7 +115,25 @@ func (c *fakeClient) List(ctx context.Context, obj runtime.Object, opts ...clien
114115
}
115116
decoder := scheme.Codecs.UniversalDecoder()
116117
_, _, err = decoder.Decode(j, nil, obj)
117-
return err
118+
if err != nil {
119+
return err
120+
}
121+
122+
if listOpts.LabelSelector != nil {
123+
objs, err := meta.ExtractList(obj)
124+
if err != nil {
125+
return err
126+
}
127+
filteredObjs, err := listutil.FilterWithLabels(objs, listOpts.LabelSelector)
128+
if err != nil {
129+
return err
130+
}
131+
err = meta.SetList(obj, filteredObjs)
132+
if err != nil {
133+
return err
134+
}
135+
}
136+
return nil
118137
}
119138

120139
func (c *fakeClient) Create(ctx context.Context, obj runtime.Object) error {

pkg/client/fake/client_test.go

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030

3131
var _ = Describe("Fake client", func() {
3232
var dep *appsv1.Deployment
33+
var dep2 *appsv1.Deployment
3334
var cm *corev1.ConfigMap
3435
var cl client.Client
3536

@@ -40,6 +41,15 @@ var _ = Describe("Fake client", func() {
4041
Namespace: "ns1",
4142
},
4243
}
44+
dep2 = &appsv1.Deployment{
45+
ObjectMeta: metav1.ObjectMeta{
46+
Name: "test-deployment-2",
47+
Namespace: "ns1",
48+
Labels: map[string]string{
49+
"test-label": "label-value",
50+
},
51+
},
52+
}
4353
cm = &corev1.ConfigMap{
4454
ObjectMeta: metav1.ObjectMeta{
4555
Name: "test-cm",
@@ -69,8 +79,20 @@ var _ = Describe("Fake client", func() {
6979
list := &appsv1.DeploymentList{}
7080
err := cl.List(nil, list, client.InNamespace("ns1"))
7181
Expect(err).To(BeNil())
82+
Expect(list.Items).To(HaveLen(2))
83+
Expect(list.Items).To(ConsistOf(*dep, *dep2))
84+
})
85+
86+
It("should support filtering by labels", func() {
87+
By("Listing deployments with a particular label")
88+
list := &appsv1.DeploymentList{}
89+
err := cl.List(nil, list, client.InNamespace("ns1"),
90+
client.MatchingLabels(map[string]string{
91+
"test-label": "label-value",
92+
}))
93+
Expect(err).To(BeNil())
7294
Expect(list.Items).To(HaveLen(1))
73-
Expect(list.Items).To(ConsistOf(*dep))
95+
Expect(list.Items).To(ConsistOf(*dep2))
7496
})
7597

7698
It("should be able to Create", func() {
@@ -129,13 +151,14 @@ var _ = Describe("Fake client", func() {
129151
list := &appsv1.DeploymentList{}
130152
err = cl.List(nil, list, client.InNamespace("ns1"))
131153
Expect(err).To(BeNil())
132-
Expect(list.Items).To(HaveLen(0))
154+
Expect(list.Items).To(HaveLen(1))
155+
Expect(list.Items).To(ConsistOf(*dep2))
133156
})
134157
}
135158

136159
Context("with default scheme.Scheme", func() {
137160
BeforeEach(func(done Done) {
138-
cl = NewFakeClient(dep, cm)
161+
cl = NewFakeClient(dep, dep2, cm)
139162
close(done)
140163
})
141164
AssertClientBehavior()
@@ -146,7 +169,7 @@ var _ = Describe("Fake client", func() {
146169
scheme := runtime.NewScheme()
147170
corev1.AddToScheme(scheme)
148171
appsv1.AddToScheme(scheme)
149-
cl = NewFakeClientWithScheme(scheme, dep, cm)
172+
cl = NewFakeClientWithScheme(scheme, dep, dep2, cm)
150173
close(done)
151174
})
152175
AssertClientBehavior()

0 commit comments

Comments
 (0)