Skip to content

Commit 00c5c79

Browse files
author
Shawn Hurley
committed
Adding two types of client for unstructured and typed
1 parent 10ed9c2 commit 00c5c79

File tree

7 files changed

+475
-175
lines changed

7 files changed

+475
-175
lines changed

pkg/cache/cache_test.go

Lines changed: 35 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ var _ = Describe("Informer Cache", func() {
117117
It("should be able to list objects that haven't been watched previously", func() {
118118
By("listing all services in the cluster")
119119
listObj := &kcorev1.ServiceList{}
120-
Expect(informerCache.List(context.Background(), listObj)).To(Succeed())
120+
Expect(informerCache.List(context.Background(), nil, listObj)).To(Succeed())
121121

122122
By("verifying that the returned list contains the Kubernetes service")
123123
// NB: kubernetes default service is automatically created in testenv.
@@ -147,10 +147,10 @@ var _ = Describe("Informer Cache", func() {
147147
By("listing pods with a particular label")
148148
// NB: each pod has a "test-label": <pod-name>
149149
out := kcorev1.PodList{}
150-
Expect(informerCache.List(context.Background(), &out,
151-
client.InNamespace(testNamespaceTwo),
152-
client.MatchingLabels(map[string]string{"test-label": "test-pod-2"}),
153-
)).To(Succeed())
150+
lo := &client.ListOptions{}
151+
lo.InNamespace(testNamespaceTwo)
152+
lo.MatchingLabels(map[string]string{"test-label": "test-pod-2"})
153+
Expect(informerCache.List(context.Background(), lo, &out)).To(Succeed())
154154

155155
By("verifying the returned pods have the correct label")
156156
Expect(out.Items).NotTo(BeEmpty())
@@ -167,9 +167,9 @@ var _ = Describe("Informer Cache", func() {
167167
// NB: each pod has a "test-label": <pod-name>
168168
out := kcorev1.PodList{}
169169
labels := map[string]string{"test-label": "test-pod-2"}
170-
Expect(informerCache.List(context.Background(), &out,
171-
client.MatchingLabels(labels),
172-
)).To(Succeed())
170+
lo := &client.ListOptions{}
171+
lo.MatchingLabels(labels)
172+
Expect(informerCache.List(context.Background(), lo, &out)).To(Succeed())
173173

174174
By("verifying multiple pods with the same label in different namespaces are returned")
175175
Expect(out.Items).NotTo(BeEmpty())
@@ -184,9 +184,9 @@ var _ = Describe("Informer Cache", func() {
184184
It("should be able to list objects by namespace", func() {
185185
By("listing pods in test-namespace-1")
186186
listObj := &kcorev1.PodList{}
187-
Expect(informerCache.List(context.Background(),
188-
client.InNamespace(testNamespaceOne),
189-
listObj)).To(Succeed())
187+
lo := &client.ListOptions{}
188+
lo.InNamespace(testNamespaceOne)
189+
Expect(informerCache.List(context.Background(), lo, listObj)).To(Succeed())
190190

191191
By("verifying that the returned pods are in test-namespace-1")
192192
Expect(listObj.Items).NotTo(BeEmpty())
@@ -231,7 +231,8 @@ var _ = Describe("Informer Cache", func() {
231231
Version: "v1",
232232
Kind: "ServiceList",
233233
})
234-
Expect(informerCache.List(context.Background(), nil, listObj)).To(Succeed())
234+
err := informerCache.List(context.Background(), nil, listObj)
235+
Expect(err).To(Succeed())
235236

236237
By("verifying that the returned list contains the Kubernetes service")
237238
// NB: kubernetes default service is automatically created in testenv.
@@ -271,8 +272,11 @@ var _ = Describe("Informer Cache", func() {
271272
Version: "v1",
272273
Kind: "PodList",
273274
})
274-
Expect(informerCache.List(context.Background(), client.InNamespace(testNamespaceTwo).
275-
MatchingLabels(map[string]string{"test-label": "test-pod-2"}), &out)).To(Succeed())
275+
lo := &client.ListOptions{}
276+
lo.InNamespace(testNamespaceTwo)
277+
lo.MatchingLabels(map[string]string{"test-label": "test-pod-2"})
278+
err := informerCache.List(context.Background(), lo, &out)
279+
Expect(err).To(Succeed())
276280

277281
By("verifying the returned pods have the correct label")
278282
Expect(out.Items).NotTo(BeEmpty())
@@ -294,8 +298,10 @@ var _ = Describe("Informer Cache", func() {
294298
Kind: "PodList",
295299
})
296300
labels := map[string]string{"test-label": "test-pod-2"}
297-
Expect(informerCache.List(context.Background(),
298-
client.MatchingLabels(labels), &out)).To(Succeed())
301+
lo := &client.ListOptions{}
302+
lo.MatchingLabels(labels)
303+
err := informerCache.List(context.Background(), lo, &out)
304+
Expect(err).To(Succeed())
299305

300306
By("verifying multiple pods with the same label in different namespaces are returned")
301307
Expect(out.Items).NotTo(BeEmpty())
@@ -315,9 +321,10 @@ var _ = Describe("Informer Cache", func() {
315321
Version: "v1",
316322
Kind: "PodList",
317323
})
318-
Expect(informerCache.List(context.Background(),
319-
client.InNamespace(testNamespaceOne),
320-
listObj)).To(Succeed())
324+
lo := &client.ListOptions{}
325+
lo.InNamespace(testNamespaceOne)
326+
err := informerCache.List(context.Background(), lo, listObj)
327+
Expect(err).To(Succeed())
321328

322329
By("verifying that the returned pods are in test-namespace-1")
323330
Expect(listObj.Items).NotTo(BeEmpty())
@@ -470,9 +477,9 @@ var _ = Describe("Informer Cache", func() {
470477

471478
By("listing Pods with restartPolicyOnFailure")
472479
listObj := &kcorev1.PodList{}
473-
Expect(informer.List(context.Background(), listObj,
474-
client.MatchingField("spec.restartPolicy", "OnFailure"),
475-
)).To(Succeed())
480+
lo := &client.ListOptions{}
481+
lo.MatchingField("spec.restartPolicy", "OnFailure")
482+
Expect(informer.List(context.Background(), lo, listObj)).To(Succeed())
476483

477484
By("verifying that the returned pods have correct restart policy")
478485
Expect(listObj.Items).NotTo(BeEmpty())
@@ -524,7 +531,7 @@ var _ = Describe("Informer Cache", func() {
524531
By("verifying the object is received on the channel")
525532
Eventually(out).Should(Receive(Equal(pod)))
526533
close(done)
527-
})
534+
}, 3)
528535

529536
It("should be able to index an object field then retrieve objects by that field", func() {
530537
By("creating the cache")
@@ -565,16 +572,17 @@ var _ = Describe("Informer Cache", func() {
565572
Version: "v1",
566573
Kind: "PodList",
567574
})
568-
Expect(informer.List(context.Background(),
569-
client.MatchingField("spec.restartPolicy", "OnFailure"),
570-
listObj)).To(Succeed())
575+
lo := &client.ListOptions{}
576+
lo.MatchingField("spec.restartPolicy", "OnFailure")
577+
err = informer.List(context.Background(), lo, listObj)
578+
Expect(err).To(Succeed())
571579

572580
By("verifying that the returned pods have correct restart policy")
573581
Expect(listObj.Items).NotTo(BeEmpty())
574582
Expect(listObj.Items).Should(HaveLen(1))
575583
actual := listObj.Items[0]
576584
Expect(actual.GetName()).To(Equal("test-pod-3"))
577-
})
585+
}, 3)
578586
})
579587
})
580588
})

pkg/cache/informer_cache.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,11 +59,6 @@ func (ip *informerCache) Get(ctx context.Context, key client.ObjectKey, out runt
5959

6060
// List implements Reader
6161
func (ip *informerCache) List(ctx context.Context, opts *client.ListOptions, out runtime.Object) error {
62-
itemsPtr, err := apimeta.GetItemsPtr(out)
63-
if err != nil {
64-
return nil
65-
}
66-
6762
gvk, err := apiutil.GVKForObject(out, ip.Scheme)
6863
if err != nil {
6964
return err

pkg/client/client.go

Lines changed: 43 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,10 @@ import (
2222
"reflect"
2323

2424
"k8s.io/apimachinery/pkg/api/meta"
25+
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
2526
"k8s.io/apimachinery/pkg/runtime"
26-
"k8s.io/apimachinery/pkg/runtime/schema"
2727
"k8s.io/apimachinery/pkg/runtime/serializer"
28+
"k8s.io/client-go/dynamic"
2829
"k8s.io/client-go/kubernetes/scheme"
2930
"k8s.io/client-go/rest"
3031
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
@@ -59,16 +60,26 @@ func New(config *rest.Config, options Options) (Client, error) {
5960
}
6061
}
6162

63+
dynamicClient, err := dynamic.NewForConfig(config)
64+
if err != nil {
65+
return nil, err
66+
}
67+
6268
c := &client{
63-
cache: clientCache{
64-
config: config,
65-
scheme: options.Scheme,
66-
mapper: options.Mapper,
67-
codecs: serializer.NewCodecFactory(options.Scheme),
68-
resourceByType: make(map[reflect.Type]*resourceMeta),
69-
unstructuredResourceByGVK: make(map[schema.GroupVersionKind]*resourceMeta),
69+
typedClient: typedClient{
70+
cache: clientCache{
71+
config: config,
72+
scheme: options.Scheme,
73+
mapper: options.Mapper,
74+
codecs: serializer.NewCodecFactory(options.Scheme),
75+
resourceByType: make(map[reflect.Type]*resourceMeta),
76+
},
77+
paramCodec: runtime.NewParameterCodec(options.Scheme),
78+
},
79+
unstructuredClient: unstructuredClient{
80+
client: dynamicClient,
81+
restMapper: options.Mapper,
7082
},
71-
paramCodec: runtime.NewParameterCodec(options.Scheme),
7283
}
7384

7485
return c, nil
@@ -79,85 +90,53 @@ var _ Client = &client{}
7990
// client is a client.Client that reads and writes directly from/to an API server. It lazily initializes
8091
// new clients at the time they are used, and caches the client.
8192
type client struct {
82-
cache clientCache
83-
paramCodec runtime.ParameterCodec
93+
typedClient typedClient
94+
unstructuredClient unstructuredClient
8495
}
8596

8697
// Create implements client.Client
8798
func (c *client) Create(ctx context.Context, obj runtime.Object) error {
88-
o, err := c.cache.getObjMeta(obj)
89-
if err != nil {
90-
return err
99+
_, ok := obj.(*unstructured.Unstructured)
100+
if ok {
101+
return c.unstructuredClient.Create(ctx, obj)
91102
}
92-
return o.Post().
93-
NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()).
94-
Resource(o.resource()).
95-
Body(obj).
96-
Do().
97-
Into(obj)
103+
return c.typedClient.Create(ctx, obj)
98104
}
99105

100106
// Update implements client.Client
101107
func (c *client) Update(ctx context.Context, obj runtime.Object) error {
102-
o, err := c.cache.getObjMeta(obj)
103-
if err != nil {
104-
return err
108+
_, ok := obj.(*unstructured.Unstructured)
109+
if ok {
110+
return c.unstructuredClient.Update(ctx, obj)
105111
}
106-
return o.Put().
107-
NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()).
108-
Resource(o.resource()).
109-
Name(o.GetName()).
110-
Body(obj).
111-
Do().
112-
Into(obj)
112+
return c.typedClient.Update(ctx, obj)
113113
}
114114

115115
// Delete implements client.Client
116116
func (c *client) Delete(ctx context.Context, obj runtime.Object, opts ...DeleteOptionFunc) error {
117-
o, err := c.cache.getObjMeta(obj)
118-
if err != nil {
119-
return err
117+
_, ok := obj.(*unstructured.Unstructured)
118+
if ok {
119+
return c.unstructuredClient.Delete(ctx, obj, opts...)
120120
}
121-
122-
deleteOpts := DeleteOptions{}
123-
return o.Delete().
124-
NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()).
125-
Resource(o.resource()).
126-
Name(o.GetName()).
127-
Body(deleteOpts.ApplyOptions(opts).AsDeleteOptions()).
128-
Do().
129-
Error()
121+
return c.typedClient.Delete(ctx, obj, opts...)
130122
}
131123

132124
// Get implements client.Client
133125
func (c *client) Get(ctx context.Context, key ObjectKey, obj runtime.Object) error {
134-
r, err := c.cache.getResource(obj)
135-
if err != nil {
136-
return err
126+
_, ok := obj.(*unstructured.Unstructured)
127+
if ok {
128+
return c.unstructuredClient.Get(ctx, key, obj)
137129
}
138-
return r.Get().
139-
NamespaceIfScoped(key.Namespace, r.isNamespaced()).
140-
Resource(r.resource()).
141-
Name(key.Name).Do().Into(obj)
130+
return c.typedClient.Get(ctx, key, obj)
142131
}
143132

144133
// List implements client.Client
145134
func (c *client) List(ctx context.Context, opts *ListOptions, obj runtime.Object) error {
146-
r, err := c.cache.getResource(obj)
147-
if err != nil {
148-
return err
135+
_, ok := obj.(*unstructured.UnstructuredList)
136+
if ok {
137+
return c.unstructuredClient.List(ctx, opts, obj)
149138
}
150-
namespace := ""
151-
if opts != nil {
152-
namespace = opts.Namespace
153-
}
154-
return r.Get().
155-
NamespaceIfScoped(namespace, r.isNamespaced()).
156-
Resource(r.resource()).
157-
Body(obj).
158-
VersionedParams(opts.AsListOptions(), c.paramCodec).
159-
Do().
160-
Into(obj)
139+
return c.typedClient.List(ctx, opts, obj)
161140
}
162141

163142
// Status implements client.StatusClient
@@ -175,7 +154,7 @@ var _ StatusWriter = &statusWriter{}
175154

176155
// Update implements client.StatusWriter
177156
func (sw *statusWriter) Update(_ context.Context, obj runtime.Object) error {
178-
o, err := sw.client.cache.getObjMeta(obj)
157+
o, err := sw.client.typedClient.cache.getObjMeta(obj)
179158
if err != nil {
180159
return err
181160
}

0 commit comments

Comments
 (0)