Skip to content

Commit a7caf15

Browse files
committed
add cluster-aware versions of gentype and listers
On-behalf-of: @SAP [email protected]
1 parent 5ae6774 commit a7caf15

File tree

4 files changed

+550
-0
lines changed

4 files changed

+550
-0
lines changed
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
/*
2+
Copyright 2024 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 gentype
18+
19+
import (
20+
"context"
21+
22+
kcptesting "github.com/kcp-dev/client-go/third_party/k8s.io/client-go/testing"
23+
"github.com/kcp-dev/logicalcluster/v3"
24+
25+
"k8s.io/apimachinery/pkg/api/meta"
26+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
27+
labels "k8s.io/apimachinery/pkg/labels"
28+
"k8s.io/apimachinery/pkg/runtime"
29+
"k8s.io/apimachinery/pkg/runtime/schema"
30+
watch "k8s.io/apimachinery/pkg/watch"
31+
)
32+
33+
// FakeClusterClient represents a fake cluster client
34+
type FakeClusterClient[T objectWithMeta] struct {
35+
*kcptesting.Fake
36+
resource schema.GroupVersionResource
37+
kind schema.GroupVersionKind
38+
newObject func() T
39+
}
40+
41+
// FakeClusterClientWithList represents a fake cluster client with support for lists.
42+
type FakeClusterClientWithList[T objectWithMeta, L runtime.Object] struct {
43+
*FakeClusterClient[T]
44+
alsoFakeClusterLister[T, L]
45+
}
46+
47+
// Helper types for composition
48+
type alsoFakeClusterLister[T objectWithMeta, L runtime.Object] struct {
49+
client *FakeClusterClient[T]
50+
newList func() L
51+
copyListMeta func(L, L)
52+
getItems func(L) []T
53+
setItems func(L, []T)
54+
}
55+
56+
// NewFakeClient constructs a fake client, namespaced or not, with no support for lists or apply.
57+
// Non-namespaced clients are constructed by passing an empty namespace ("").
58+
func NewFakeClusterClient[T objectWithMeta](
59+
fake *kcptesting.Fake, resource schema.GroupVersionResource, kind schema.GroupVersionKind, emptyObjectCreator func() T,
60+
) *FakeClusterClient[T] {
61+
return &FakeClusterClient[T]{fake, resource, kind, emptyObjectCreator}
62+
}
63+
64+
// NewFakeClusterClientWithList constructs a namespaced client with support for lists.
65+
func NewFakeClusterClientWithList[T objectWithMeta, L runtime.Object](
66+
fake *kcptesting.Fake, resource schema.GroupVersionResource, kind schema.GroupVersionKind, emptyObjectCreator func() T,
67+
emptyListCreator func() L, listMetaCopier func(L, L), itemGetter func(L) []T, itemSetter func(L, []T),
68+
) *FakeClusterClientWithList[T, L] {
69+
fakeClusterClient := NewFakeClusterClient[T](fake, resource, kind, emptyObjectCreator)
70+
return &FakeClusterClientWithList[T, L]{
71+
fakeClusterClient,
72+
alsoFakeClusterLister[T, L]{fakeClusterClient, emptyListCreator, listMetaCopier, itemGetter, itemSetter},
73+
}
74+
}
75+
76+
// List takes label and field selectors, and returns the list of resources that match those selectors.
77+
func (l *alsoFakeClusterLister[T, L]) List(ctx context.Context, opts metav1.ListOptions) (result L, err error) {
78+
emptyResult := l.newList()
79+
obj, err := l.client.Fake.
80+
Invokes(kcptesting.NewListAction(l.client.resource, l.client.kind, logicalcluster.Wildcard, metav1.NamespaceAll, opts), emptyResult)
81+
if obj == nil {
82+
return emptyResult, err
83+
}
84+
85+
label, _, _ := kcptesting.ExtractFromListOptions(opts)
86+
if label == nil {
87+
// Everything matches
88+
return obj.(L), nil
89+
}
90+
list := l.newList()
91+
l.copyListMeta(list, obj.(L))
92+
var items []T
93+
for _, item := range l.getItems(obj.(L)) {
94+
itemMeta, err := meta.Accessor(item)
95+
if err != nil {
96+
// No ObjectMeta, nothing can match
97+
continue
98+
}
99+
if label.Matches(labels.Set(itemMeta.GetLabels())) {
100+
items = append(items, item)
101+
}
102+
}
103+
l.setItems(list, items)
104+
return list, err
105+
}
106+
107+
// Watch returns a watch.Interface that watches the requested resources.
108+
func (c *FakeClusterClient[T]) Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) {
109+
opts.Watch = true
110+
return c.Fake.
111+
InvokesWatch(kcptesting.NewWatchAction(c.resource, logicalcluster.Wildcard, metav1.NamespaceAll, opts))
112+
}
113+
114+
func (c *FakeClusterClient[T]) Kind() schema.GroupVersionKind {
115+
return c.kind
116+
}
117+
118+
func (c *FakeClusterClient[T]) Resource() schema.GroupVersionResource {
119+
return c.resource
120+
}

0 commit comments

Comments
 (0)