Skip to content

Commit

Permalink
Merge pull request #1058 from vincepri/expose-client-scheme
Browse files Browse the repository at this point in the history
⚠ Expose Client runtime.Scheme
  • Loading branch information
k8s-ci-robot committed Aug 4, 2020
2 parents cfdc32f + e263d2c commit e83442f
Show file tree
Hide file tree
Showing 9 changed files with 127 additions and 50 deletions.
7 changes: 7 additions & 0 deletions pkg/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ func New(config *rest.Config, options Options) (Client, error) {
cache: clientcache,
paramCodec: noConversionParamCodec{},
},
scheme: options.Scheme,
}

return c, nil
Expand All @@ -97,6 +98,7 @@ var _ Client = &client{}
type client struct {
typedClient typedClient
unstructuredClient unstructuredClient
scheme *runtime.Scheme
}

// resetGroupVersionKind is a helper function to restore and preserve GroupVersionKind on an object.
Expand All @@ -109,6 +111,11 @@ func (c *client) resetGroupVersionKind(obj runtime.Object, gvk schema.GroupVersi
}
}

// Scheme returns the scheme this client is using.
func (c *client) Scheme() *runtime.Scheme {
return c.scheme
}

// Create implements client.Client
func (c *client) Create(ctx context.Context, obj runtime.Object, opts ...CreateOption) error {
_, ok := obj.(*unstructured.Unstructured)
Expand Down
100 changes: 67 additions & 33 deletions pkg/client/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2625,62 +2625,96 @@ var _ = Describe("Client", func() {
})
})

var _ = Describe("DelegatingReader", func() {
var _ = Describe("DelegatingClient", func() {
Describe("Get", func() {
It("should call cache reader when structured object", func() {
cachedReader := &fakeReader{}
clientReader := &fakeReader{}
dReader := client.DelegatingReader{
CacheReader: cachedReader,
ClientReader: clientReader,
}
cl, err := client.New(cfg, client.Options{})
Expect(err).NotTo(HaveOccurred())
dReader := client.NewDelegatingClient(client.NewDelegatingClientInput{
CacheReader: cachedReader,
Client: cl,
})
var actual appsv1.Deployment
key := client.ObjectKey{Namespace: "ns", Name: "name"}
Expect(dReader.Get(context.TODO(), key, &actual)).To(Succeed())
Expect(1).To(Equal(cachedReader.Called))
Expect(0).To(Equal(clientReader.Called))
})
It("should call client reader when structured object", func() {

It("should call client reader when unstructured object", func() {
cachedReader := &fakeReader{}
clientReader := &fakeReader{}
dReader := client.DelegatingReader{
CacheReader: cachedReader,
ClientReader: clientReader,
cl, err := client.New(cfg, client.Options{})
Expect(err).NotTo(HaveOccurred())
dReader := client.NewDelegatingClient(client.NewDelegatingClientInput{
CacheReader: cachedReader,
Client: cl,
})
dep := &appsv1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: "deployment1",
Labels: map[string]string{"app": "frontend"},
},
Spec: appsv1.DeploymentSpec{
Selector: &metav1.LabelSelector{
MatchLabels: map[string]string{"app": "frontend"},
},
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "frontend"}},
Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "x", Image: "x"}}},
},
},
}
var actual unstructured.Unstructured
key := client.ObjectKey{Namespace: "ns", Name: "name"}
Expect(dReader.Get(context.TODO(), key, &actual)).To(Succeed())
dep, err = clientset.AppsV1().Deployments("default").Create(context.Background(), dep, metav1.CreateOptions{})
Expect(err).NotTo(HaveOccurred())

actual := &unstructured.Unstructured{}
actual.SetGroupVersionKind(schema.GroupVersionKind{
Group: "apps",
Kind: "Deployment",
Version: "v1",
})
actual.SetName(dep.Name)
key := client.ObjectKey{Namespace: dep.Namespace, Name: dep.Name}
Expect(dReader.Get(context.TODO(), key, actual)).To(Succeed())
Expect(0).To(Equal(cachedReader.Called))
Expect(1).To(Equal(clientReader.Called))
Expect(clientset.AppsV1().Deployments("default").Delete(
context.Background(),
dep.Name,
metav1.DeleteOptions{},
)).To(Succeed())
})
})
Describe("List", func() {
It("should call cache reader when structured object", func() {
cachedReader := &fakeReader{}
clientReader := &fakeReader{}
dReader := client.DelegatingReader{
CacheReader: cachedReader,
ClientReader: clientReader,
}
cl, err := client.New(cfg, client.Options{})
Expect(err).NotTo(HaveOccurred())
dReader := client.NewDelegatingClient(client.NewDelegatingClientInput{
CacheReader: cachedReader,
Client: cl,
})
var actual appsv1.DeploymentList
Expect(dReader.List(context.Background(), &actual)).To(Succeed())
Expect(1).To(Equal(cachedReader.Called))
Expect(0).To(Equal(clientReader.Called))

})
It("should call client reader when structured object", func() {

It("should call client reader when unstructured object", func() {
cachedReader := &fakeReader{}
clientReader := &fakeReader{}
dReader := client.DelegatingReader{
CacheReader: cachedReader,
ClientReader: clientReader,
}
cl, err := client.New(cfg, client.Options{})
Expect(err).NotTo(HaveOccurred())
dReader := client.NewDelegatingClient(client.NewDelegatingClientInput{
CacheReader: cachedReader,
Client: cl,
})

var actual unstructured.UnstructuredList
Expect(dReader.List(context.Background(), &actual)).To(Succeed())
actual := &unstructured.UnstructuredList{}
actual.SetGroupVersionKind(schema.GroupVersionKind{
Group: "apps",
Kind: "DeploymentList",
Version: "v1",
})
Expect(dReader.List(context.Background(), actual)).To(Succeed())
Expect(0).To(Equal(cachedReader.Called))
Expect(1).To(Equal(clientReader.Called))

})
})
})
Expand Down
5 changes: 5 additions & 0 deletions pkg/client/dryrun.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ type dryRunClient struct {
client Client
}

// Scheme returns the scheme this client is using.
func (c *dryRunClient) Scheme() *runtime.Scheme {
return c.client.Scheme()
}

// Create implements client.Client
func (c *dryRunClient) Create(ctx context.Context, obj runtime.Object, opts ...CreateOption) error {
return c.client.Create(ctx, obj, append(opts, DryRunAll)...)
Expand Down
2 changes: 1 addition & 1 deletion pkg/client/example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ func ExampleClient_create() {
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
corev1.Container{
{
Image: "nginx",
Name: "nginx",
},
Expand Down
4 changes: 4 additions & 0 deletions pkg/client/fake/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,10 @@ func (c *fakeClient) List(ctx context.Context, obj runtime.Object, opts ...clien
return nil
}

func (c *fakeClient) Scheme() *runtime.Scheme {
return c.scheme
}

func (c *fakeClient) Create(ctx context.Context, obj runtime.Object, opts ...client.CreateOption) error {
createOptions := &client.CreateOptions{}
createOptions.ApplyOptions(opts)
Expand Down
3 changes: 3 additions & 0 deletions pkg/client/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,9 @@ type Client interface {
Reader
Writer
StatusClient

// Scheme returns the scheme this client is using.
Scheme() *runtime.Scheme
}

// IndexerFunc knows how to take an object and turn it into a series
Expand Down
40 changes: 34 additions & 6 deletions pkg/client/split.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,27 +23,55 @@ import (
"k8s.io/apimachinery/pkg/runtime"
)

// DelegatingClient forms a Client by composing separate reader, writer and
// NewDelegatingClientInput encapsulates the input parameters to create a new delegating client.
type NewDelegatingClientInput struct {
Scheme *runtime.Scheme
CacheReader Reader
Client Client
}

// NewDelegatingClient creates a new delegating client.
//
// A delegating client forms a Client by composing separate reader, writer and
// statusclient interfaces. This way, you can have an Client that reads from a
// cache and writes to the API server.
type DelegatingClient struct {
func NewDelegatingClient(in NewDelegatingClientInput) Client {
return &delegatingClient{
scheme: in.Scheme,
Reader: &delegatingReader{
CacheReader: in.CacheReader,
ClientReader: in.Client,
},
Writer: in.Client,
StatusClient: in.Client,
}
}

type delegatingClient struct {
Reader
Writer
StatusClient

scheme *runtime.Scheme
}

// Scheme returns the scheme this client is using.
func (d *delegatingClient) Scheme() *runtime.Scheme {
return d.scheme
}

// DelegatingReader forms a Reader that will cause Get and List requests for
// delegatingReader forms a Reader that will cause Get and List requests for
// unstructured types to use the ClientReader while requests for any other type
// of object with use the CacheReader. This avoids accidentally caching the
// entire cluster in the common case of loading arbitrary unstructured objects
// (e.g. from OwnerReferences).
type DelegatingReader struct {
type delegatingReader struct {
CacheReader Reader
ClientReader Reader
}

// Get retrieves an obj for a given object key from the Kubernetes Cluster.
func (d *DelegatingReader) Get(ctx context.Context, key ObjectKey, obj runtime.Object) error {
func (d *delegatingReader) Get(ctx context.Context, key ObjectKey, obj runtime.Object) error {
_, isUnstructured := obj.(*unstructured.Unstructured)
if isUnstructured {
return d.ClientReader.Get(ctx, key, obj)
Expand All @@ -52,7 +80,7 @@ func (d *DelegatingReader) Get(ctx context.Context, key ObjectKey, obj runtime.O
}

// List retrieves list of objects for a given namespace and list options.
func (d *DelegatingReader) List(ctx context.Context, list runtime.Object, opts ...ListOption) error {
func (d *delegatingReader) List(ctx context.Context, list runtime.Object, opts ...ListOption) error {
_, isUnstructured := list.(*unstructured.UnstructuredList)
if isUnstructured {
return d.ClientReader.List(ctx, list, opts...)
Expand Down
12 changes: 4 additions & 8 deletions pkg/manager/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -378,14 +378,10 @@ func DefaultNewClient(cache cache.Cache, config *rest.Config, options client.Opt
return nil, err
}

return &client.DelegatingClient{
Reader: &client.DelegatingReader{
CacheReader: cache,
ClientReader: c,
},
Writer: c,
StatusClient: c,
}, nil
return client.NewDelegatingClient(client.NewDelegatingClientInput{
CacheReader: cache,
Client: c,
}), nil
}

// defaultHealthProbeListener creates the default health probes listener bound to the given address
Expand Down
4 changes: 2 additions & 2 deletions pkg/runtime/inject/inject_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ var _ = Describe("runtime inject", func() {
})

It("should set client", func() {
client := client.DelegatingClient{}
client := client.NewDelegatingClient(client.NewDelegatingClientInput{})

By("Validating injecting client")
res, err := ClientInto(client, instance)
Expand Down Expand Up @@ -151,7 +151,7 @@ var _ = Describe("runtime inject", func() {
})

It("should set api reader", func() {
apiReader := &client.DelegatingReader{}
apiReader := client.NewDelegatingClient(client.NewDelegatingClientInput{})

By("Validating injecting client")
res, err := APIReaderInto(apiReader, instance)
Expand Down

0 comments on commit e83442f

Please sign in to comment.