Skip to content

Commit

Permalink
Enable labels list options in fake client
Browse files Browse the repository at this point in the history
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 `objectutil.FilterWithLabels`.

Signed-off-by: sebgl <contact.sebgl@gmail.com>
  • Loading branch information
sebgl committed Jan 31, 2019
1 parent 6d1ee71 commit bc400f2
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 27 deletions.
31 changes: 9 additions & 22 deletions pkg/cache/internal/cache_reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
"k8s.io/apimachinery/pkg/selection"
"k8s.io/client-go/tools/cache"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/internal/objectutil"
)

// CacheReader is a CacheReader
Expand Down Expand Up @@ -118,33 +119,19 @@ func (c *CacheReader) List(_ context.Context, out runtime.Object, opts ...client
labelSel = listOpts.LabelSelector
}

outItems, err := c.getListItems(objs, labelSel)
if err != nil {
return err
}
return apimeta.SetList(out, outItems)
}

func (c *CacheReader) getListItems(objs []interface{}, labelSel labels.Selector) ([]runtime.Object, error) {
outItems := make([]runtime.Object, 0, len(objs))
runtimeObjs := make([]runtime.Object, 0, len(objs))
for _, item := range objs {
obj, isObj := item.(runtime.Object)
if !isObj {
return nil, fmt.Errorf("cache contained %T, which is not an Object", obj)
return fmt.Errorf("cache contained %T, which is not an Object", obj)
}
meta, err := apimeta.Accessor(obj)
if err != nil {
return nil, err
}
if labelSel != nil {
lbls := labels.Set(meta.GetLabels())
if !labelSel.Matches(lbls) {
continue
}
}
outItems = append(outItems, obj.DeepCopyObject())
runtimeObjs = append(runtimeObjs, obj)
}
filteredItems, err := objectutil.FilterWithLabels(runtimeObjs, labelSel)
if err != nil {
return err
}
return outItems, nil
return apimeta.SetList(out, filteredItems)
}

// objectKeyToStorageKey converts an object key to store key.
Expand Down
21 changes: 20 additions & 1 deletion pkg/client/fake/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
logf "sigs.k8s.io/controller-runtime/pkg/internal/log"
"sigs.k8s.io/controller-runtime/pkg/internal/objectutil"
)

var (
Expand Down Expand Up @@ -114,7 +115,25 @@ func (c *fakeClient) List(ctx context.Context, obj runtime.Object, opts ...clien
}
decoder := scheme.Codecs.UniversalDecoder()
_, _, err = decoder.Decode(j, nil, obj)
return err
if err != nil {
return err
}

if listOpts.LabelSelector != nil {
objs, err := meta.ExtractList(obj)
if err != nil {
return err
}
filteredObjs, err := objectutil.FilterWithLabels(objs, listOpts.LabelSelector)
if err != nil {
return err
}
err = meta.SetList(obj, filteredObjs)
if err != nil {
return err
}
}
return nil
}

func (c *fakeClient) Create(ctx context.Context, obj runtime.Object) error {
Expand Down
31 changes: 27 additions & 4 deletions pkg/client/fake/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (

var _ = Describe("Fake client", func() {
var dep *appsv1.Deployment
var dep2 *appsv1.Deployment
var cm *corev1.ConfigMap
var cl client.Client

Expand All @@ -40,6 +41,15 @@ var _ = Describe("Fake client", func() {
Namespace: "ns1",
},
}
dep2 = &appsv1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: "test-deployment-2",
Namespace: "ns1",
Labels: map[string]string{
"test-label": "label-value",
},
},
}
cm = &corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "test-cm",
Expand Down Expand Up @@ -69,8 +79,20 @@ var _ = Describe("Fake client", func() {
list := &appsv1.DeploymentList{}
err := cl.List(nil, list, client.InNamespace("ns1"))
Expect(err).To(BeNil())
Expect(list.Items).To(HaveLen(2))
Expect(list.Items).To(ConsistOf(*dep, *dep2))
})

It("should support filtering by labels", func() {
By("Listing deployments with a particular label")
list := &appsv1.DeploymentList{}
err := cl.List(nil, list, client.InNamespace("ns1"),
client.MatchingLabels(map[string]string{
"test-label": "label-value",
}))
Expect(err).To(BeNil())
Expect(list.Items).To(HaveLen(1))
Expect(list.Items).To(ConsistOf(*dep))
Expect(list.Items).To(ConsistOf(*dep2))
})

It("should be able to Create", func() {
Expand Down Expand Up @@ -129,13 +151,14 @@ var _ = Describe("Fake client", func() {
list := &appsv1.DeploymentList{}
err = cl.List(nil, list, client.InNamespace("ns1"))
Expect(err).To(BeNil())
Expect(list.Items).To(HaveLen(0))
Expect(list.Items).To(HaveLen(1))
Expect(list.Items).To(ConsistOf(*dep2))
})
}

Context("with default scheme.Scheme", func() {
BeforeEach(func(done Done) {
cl = NewFakeClient(dep, cm)
cl = NewFakeClient(dep, dep2, cm)
close(done)
})
AssertClientBehavior()
Expand All @@ -146,7 +169,7 @@ var _ = Describe("Fake client", func() {
scheme := runtime.NewScheme()
corev1.AddToScheme(scheme)
appsv1.AddToScheme(scheme)
cl = NewFakeClientWithScheme(scheme, dep, cm)
cl = NewFakeClientWithScheme(scheme, dep, dep2, cm)
close(done)
})
AssertClientBehavior()
Expand Down
42 changes: 42 additions & 0 deletions pkg/internal/objectutil/filter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package objectutil

import (
apimeta "k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
)

// FilterWithLabels returns a copy of the items in objs matching labelSel
func FilterWithLabels(objs []runtime.Object, labelSel labels.Selector) ([]runtime.Object, error) {
outItems := make([]runtime.Object, 0, len(objs))
for _, obj := range objs {
meta, err := apimeta.Accessor(obj)
if err != nil {
return nil, err
}
if labelSel != nil {
lbls := labels.Set(meta.GetLabels())
if !labelSel.Matches(lbls) {
continue
}
}
outItems = append(outItems, obj.DeepCopyObject())
}
return outItems, nil
}

0 comments on commit bc400f2

Please sign in to comment.