Skip to content

Commit d791801

Browse files
committed
client tests part 1
1 parent 985614c commit d791801

File tree

11 files changed

+618
-57
lines changed

11 files changed

+618
-57
lines changed

pkg/cache/cache.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ import (
3737

3838
var log = logf.KBLog.WithName("object-cache")
3939

40-
// objectCache is a ReadInterface
41-
var _ client.ReadInterface = &objectCache{}
40+
// objectCache is a Reader
41+
var _ client.Reader = &objectCache{}
4242

4343
// objectCache is a Kubernetes Object cache populated from Informers
4444
type objectCache struct {
@@ -47,7 +47,7 @@ type objectCache struct {
4747
informers *informers
4848
}
4949

50-
var _ client.ReadInterface = &objectCache{}
50+
var _ client.Reader = &objectCache{}
5151

5252
// addInformer adds an informer to the objectCache
5353
func (o *objectCache) addInformer(gvk schema.GroupVersionKind, c cache.SharedIndexInformer) {
@@ -106,7 +106,7 @@ func (o *objectCache) cacheFor(obj runtime.Object) (*singleObjectCache, error) {
106106
return cache, nil
107107
}
108108

109-
// Get implements populatingClient.ReadInterface
109+
// Get implements populatingClient.Reader
110110
func (o *objectCache) Get(ctx context.Context, key client.ObjectKey, out runtime.Object) error {
111111
// Make sure there is a Cache for this type
112112
if !o.has(out) {
@@ -124,7 +124,7 @@ func (o *objectCache) Get(ctx context.Context, key client.ObjectKey, out runtime
124124
return cache.Get(ctx, key, out)
125125
}
126126

127-
// List implements populatingClient.ReadInterface
127+
// List implements populatingClient.Reader
128128
func (o *objectCache) List(ctx context.Context, opts *client.ListOptions, out runtime.Object) error {
129129
itemsPtr, err := apimeta.GetItemsPtr(out)
130130
if err != nil {
@@ -148,10 +148,10 @@ func (o *objectCache) List(ctx context.Context, opts *client.ListOptions, out ru
148148
return cache.List(ctx, opts, out)
149149
}
150150

151-
// singleObjectCache is a ReadInterface
152-
var _ client.ReadInterface = &singleObjectCache{}
151+
// singleObjectCache is a Reader
152+
var _ client.Reader = &singleObjectCache{}
153153

154-
// singleObjectCache is a ReadInterface that retrieves objects
154+
// singleObjectCache is a Reader that retrieves objects
155155
// from a single local cache populated by a watch.
156156
type singleObjectCache struct {
157157
// Indexer is the underlying indexer wrapped by this cache.

pkg/cache/cache_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ var _ = Describe("Indexers", func() {
8787
})
8888

8989
Describe("populatingClient interface wrapper around an indexer", func() {
90-
var singleCache client.ReadInterface
90+
var singleCache client.Reader
9191

9292
BeforeEach(func() {
9393
var err error

pkg/cache/informer.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ import (
1919
"k8s.io/client-go/tools/cache"
2020
)
2121

22-
// Cache implements ReadInterface by reading objects from a cache populated by Informers
22+
// Cache implements Reader by reading objects from a cache populated by Informers
2323
type Cache interface {
24-
client.ReadInterface
24+
client.Reader
2525
Informers
2626
IndexField(obj runtime.Object, field string, extractValue client.IndexerFunc) error
2727
}

pkg/client/client.go

Lines changed: 99 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,34 @@
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+
117
package client
218

319
import (
420
"context"
21+
"fmt"
522
"reflect"
623
"sync"
724

25+
"github.com/kubernetes-sigs/controller-runtime/pkg/client/apiutil"
826
"k8s.io/apimachinery/pkg/api/meta"
27+
"k8s.io/apimachinery/pkg/apis/meta/v1"
928
"k8s.io/apimachinery/pkg/runtime"
10-
serializer "k8s.io/apimachinery/pkg/runtime/serializer"
29+
"k8s.io/apimachinery/pkg/runtime/serializer"
1130
"k8s.io/client-go/kubernetes/scheme"
1231
"k8s.io/client-go/rest"
13-
14-
"github.com/kubernetes-sigs/controller-runtime/pkg/client/apiutil"
15-
"k8s.io/apimachinery/pkg/apis/meta/v1"
1632
)
1733

1834
// Options are creation options for a Client
@@ -26,6 +42,10 @@ type Options struct {
2642

2743
// New returns a new Client using the provided config and Options.
2844
func New(config *rest.Config, options Options) (Client, error) {
45+
if config == nil {
46+
return nil, fmt.Errorf("must provide non-nil rest.Config to client.New")
47+
}
48+
2949
// Init a scheme if none provided
3050
if options.Scheme == nil {
3151
options.Scheme = scheme.Scheme
@@ -48,6 +68,7 @@ func New(config *rest.Config, options Options) (Client, error) {
4868
paramCodec: runtime.NewParameterCodec(options.Scheme),
4969
clientsByType: make(map[reflect.Type]rest.Interface),
5070
resourcesByType: make(map[reflect.Type]string),
71+
mappingByType: make(map[reflect.Type]*meta.RESTMapping),
5172
}
5273

5374
return c, nil
@@ -65,74 +86,94 @@ type populatingClient struct {
6586
codecs serializer.CodecFactory
6687
paramCodec runtime.ParameterCodec
6788
clientsByType map[reflect.Type]rest.Interface
89+
mappingByType map[reflect.Type]*meta.RESTMapping
6890
resourcesByType map[reflect.Type]string
6991
mu sync.RWMutex
7092
}
7193

7294
// makeClient maps obj to a Kubernetes Resource and constructs a populatingClient for that Resource.
73-
func (c *populatingClient) makeClient(obj runtime.Object) (rest.Interface, string, error) {
95+
func (c *populatingClient) makeClient(obj runtime.Object) (rest.Interface, *meta.RESTMapping, string, error) {
7496
gvk, err := apiutil.GVKForObject(obj, c.scheme)
7597
if err != nil {
76-
return nil, "", err
98+
return nil, nil, "", err
7799
}
78100
client, err := apiutil.RESTClientForGVK(gvk, c.config, c.codecs)
79101
if err != nil {
80-
return nil, "", err
102+
return nil, nil, "", err
81103
}
82104
mapping, err := c.mapper.RESTMapping(gvk.GroupKind(), gvk.Version)
83105
if err != nil {
84-
return nil, "", err
106+
return nil, nil, "", err
85107
}
86-
return client, mapping.Resource, nil
108+
return client, mapping, mapping.Resource, nil
87109
}
88110

89111
// clientFor returns a raw rest.Client for the given object type.
90-
func (c *populatingClient) clientFor(obj runtime.Object) (rest.Interface, string, error) {
112+
func (c *populatingClient) clientFor(obj runtime.Object) (rest.Interface, *meta.RESTMapping, string, error) {
91113
typ := reflect.TypeOf(obj)
92114

93115
// It's better to do creation work twice than to not let multiple
94116
// people make requests at once
95117
c.mu.RLock()
96118
client, known := c.clientsByType[typ]
97119
resource, _ := c.resourcesByType[typ]
120+
mapping, _ := c.mappingByType[typ]
98121
c.mu.RUnlock()
99122

100123
// Initialize a new Client
101124
if !known {
102125
var err error
103-
client, resource, err = c.makeClient(obj)
126+
client, mapping, resource, err = c.makeClient(obj)
104127
if err != nil {
105-
return nil, "", err
128+
return nil, mapping, "", err
106129
}
107130
c.mu.Lock()
108131
defer c.mu.Unlock()
109132
c.clientsByType[typ] = client
110133
c.resourcesByType[typ] = resource
134+
c.mappingByType[typ] = mapping
111135
}
112136

113-
return client, resource, nil
137+
return client, mapping, resource, nil
114138
}
115139

116-
func (c *populatingClient) metaAndClientFor(obj runtime.Object) (v1.Object, rest.Interface, string, error) {
117-
client, resource, err := c.clientFor(obj)
140+
func (c *populatingClient) metaAndClientFor(obj runtime.Object) (v1.Object, rest.Interface, *meta.RESTMapping, string, error) {
141+
client, mapping, resource, err := c.clientFor(obj)
118142
if err != nil {
119-
return nil, nil, "", err
143+
return nil, nil, nil, "", err
120144
}
145+
121146
meta, err := meta.Accessor(obj)
122147
if err != nil {
123-
return nil, nil, "", err
148+
return nil, nil, nil, "", err
124149
}
125-
return meta, client, resource, err
150+
return meta, client, mapping, resource, err
151+
}
152+
153+
func isNamespaced(mapping *meta.RESTMapping) bool {
154+
if mapping.Scope.Name() == meta.RESTScopeNameRoot {
155+
return false
156+
}
157+
return true
126158
}
127159

128160
// Create implements Client
129161
func (c *populatingClient) Create(ctx context.Context, obj runtime.Object) error {
130-
meta, client, resource, err := c.metaAndClientFor(obj)
162+
meta, client, mapping, resource, err := c.metaAndClientFor(obj)
131163
if err != nil {
132164
return err
133165
}
166+
167+
if isNamespaced(mapping) {
168+
return client.Post().
169+
Namespace(meta.GetNamespace()).
170+
Resource(resource).
171+
Body(obj).
172+
Do().
173+
Into(obj)
174+
}
175+
134176
return client.Post().
135-
Namespace(meta.GetNamespace()).
136177
Resource(resource).
137178
Body(obj).
138179
Do().
@@ -141,12 +182,21 @@ func (c *populatingClient) Create(ctx context.Context, obj runtime.Object) error
141182

142183
// Update implements Client
143184
func (c *populatingClient) Update(ctx context.Context, obj runtime.Object) error {
144-
meta, client, resource, err := c.metaAndClientFor(obj)
185+
meta, client, mapping, resource, err := c.metaAndClientFor(obj)
145186
if err != nil {
146187
return err
147188
}
189+
if isNamespaced(mapping) {
190+
return client.Put().
191+
Namespace(meta.GetNamespace()).
192+
Resource(resource).
193+
Name(meta.GetName()).
194+
Body(obj).
195+
Do().
196+
Into(obj)
197+
}
198+
148199
return client.Put().
149-
Namespace(meta.GetNamespace()).
150200
Resource(resource).
151201
Name(meta.GetName()).
152202
Body(obj).
@@ -156,12 +206,19 @@ func (c *populatingClient) Update(ctx context.Context, obj runtime.Object) error
156206

157207
// Delete implements Client
158208
func (c *populatingClient) Delete(ctx context.Context, obj runtime.Object) error {
159-
meta, client, resource, err := c.metaAndClientFor(obj)
209+
meta, client, mapping, resource, err := c.metaAndClientFor(obj)
160210
if err != nil {
161211
return err
162212
}
213+
if isNamespaced(mapping) {
214+
return client.Delete().
215+
Namespace(meta.GetNamespace()).
216+
Resource(resource).
217+
Name(meta.GetName()).
218+
Do().
219+
Error()
220+
}
163221
return client.Delete().
164-
Namespace(meta.GetNamespace()).
165222
Resource(resource).
166223
Name(meta.GetName()).
167224
Do().
@@ -170,12 +227,19 @@ func (c *populatingClient) Delete(ctx context.Context, obj runtime.Object) error
170227

171228
// Get implements Client
172229
func (c *populatingClient) Get(ctx context.Context, key ObjectKey, obj runtime.Object) error {
173-
client, resource, err := c.clientFor(obj)
230+
_, client, mapping, resource, err := c.metaAndClientFor(obj)
174231
if err != nil {
175232
return err
176233
}
234+
if isNamespaced(mapping) {
235+
return client.Get().
236+
Namespace(key.Namespace).
237+
Resource(resource).
238+
Name(key.Name).
239+
Do().
240+
Into(obj)
241+
}
177242
return client.Get().
178-
Namespace(key.Namespace).
179243
Resource(resource).
180244
Name(key.Name).
181245
Do().
@@ -184,16 +248,20 @@ func (c *populatingClient) Get(ctx context.Context, key ObjectKey, obj runtime.O
184248

185249
// List implements Client
186250
func (c *populatingClient) List(ctx context.Context, opts *ListOptions, obj runtime.Object) error {
187-
client, resource, err := c.clientFor(obj)
251+
_, client, mapping, resource, err := c.metaAndClientFor(obj)
188252
if err != nil {
189253
return err
190254
}
191-
ns := ""
192-
if opts != nil {
193-
ns = opts.Namespace
255+
if isNamespaced(mapping) && opts != nil && len(opts.Namespace) > 0 {
256+
return client.Get().
257+
Namespace(opts.Namespace).
258+
Resource(resource).
259+
Body(obj).
260+
VersionedParams(opts.AsListOptions(), c.paramCodec).
261+
Do().
262+
Into(obj)
194263
}
195264
return client.Get().
196-
Namespace(ns).
197265
Resource(resource).
198266
Body(obj).
199267
VersionedParams(opts.AsListOptions(), c.paramCodec).

pkg/client/client_suite_test.go

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,60 @@
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+
117
package client_test
218

319
import (
420
"testing"
21+
"time"
522

23+
"github.com/kubernetes-sigs/controller-runtime/pkg/test"
624
. "github.com/onsi/ginkgo"
725
. "github.com/onsi/gomega"
26+
"k8s.io/client-go/kubernetes"
27+
"k8s.io/client-go/rest"
28+
29+
logf "github.com/kubernetes-sigs/controller-runtime/pkg/runtime/log"
830
)
931

10-
func TestEventhandler(t *testing.T) {
32+
func TestSource(t *testing.T) {
1133
RegisterFailHandler(Fail)
12-
RunSpecs(t, "client tests")
34+
RunSpecsWithDefaultAndCustomReporters(t, "Controller Integration Suite", []Reporter{test.NewlineReporter{}})
1335
}
36+
37+
var testenv *test.Environment
38+
var cfg *rest.Config
39+
var clientset *kubernetes.Clientset
40+
41+
var _ = BeforeSuite(func(done Done) {
42+
logf.SetLogger(logf.ZapLogger(false))
43+
44+
testenv = &test.Environment{}
45+
46+
var err error
47+
cfg, err = testenv.Start()
48+
Expect(err).NotTo(HaveOccurred())
49+
50+
time.Sleep(1 * time.Second)
51+
52+
clientset, err = kubernetes.NewForConfig(cfg)
53+
Expect(err).NotTo(HaveOccurred())
54+
55+
close(done)
56+
}, 60)
57+
58+
var _ = AfterSuite(func() {
59+
testenv.Stop()
60+
})

0 commit comments

Comments
 (0)