Skip to content

Commit c547d2c

Browse files
committed
revised status subresource interface
1 parent 9d34003 commit c547d2c

File tree

6 files changed

+67
-34
lines changed

6 files changed

+67
-34
lines changed

pkg/client/client.go

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -110,24 +110,6 @@ func (c *client) Update(ctx context.Context, obj runtime.Object) error {
110110
Into(obj)
111111
}
112112

113-
// UpdateStatus implements client.Client
114-
func (c *client) UpdateStatus(ctx context.Context, obj runtime.Object) error {
115-
o, err := c.cache.getObjMeta(obj)
116-
if err != nil {
117-
return err
118-
}
119-
// TODO(droot): examine the returned error and check if it error needs to be
120-
// wrapped to improve the UX ?
121-
return o.Put().
122-
NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()).
123-
Resource(o.resource()).
124-
Name(o.GetName()).
125-
SubResource("status").
126-
Body(obj).
127-
Do().
128-
Into(obj)
129-
}
130-
131113
// Delete implements client.Client
132114
func (c *client) Delete(ctx context.Context, obj runtime.Object) error {
133115
o, err := c.cache.getObjMeta(obj)
@@ -172,3 +154,36 @@ func (c *client) List(ctx context.Context, opts *ListOptions, obj runtime.Object
172154
Do().
173155
Into(obj)
174156
}
157+
158+
// Status returns client.StatusClient
159+
func (c *client) Status() StatusWriter {
160+
return &statusWriter{client: c}
161+
}
162+
163+
// statusWriter is client.StatusWriter that writes status subresource
164+
type statusWriter struct {
165+
client *client
166+
}
167+
168+
// ensure statusWriter implements client.StatusWriter
169+
var _ StatusWriter = &statusWriter{}
170+
171+
// Update implements client.StatusWriter
172+
func (sw *statusWriter) Update(_ context.Context, obj runtime.Object) error {
173+
o, err := sw.client.cache.getObjMeta(obj)
174+
if err != nil {
175+
return err
176+
}
177+
// TODO(droot): examine the returned error and check if it error needs to be
178+
// wrapped to improve the UX ?
179+
// It will be nice to receive an error saying the object doesn't implement
180+
// status subresource and check CRD definition
181+
return o.Put().
182+
NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()).
183+
Resource(o.resource()).
184+
Name(o.GetName()).
185+
SubResource("status").
186+
Body(obj).
187+
Do().
188+
Into(obj)
189+
}

pkg/client/client_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,7 @@ var _ = Describe("Client", func() {
393393
})
394394
})
395395

396-
Describe("UpdateStatus", func() {
396+
Describe("StatusClient", func() {
397397
It("should update status of an existing object", func(done Done) {
398398
cl, err := client.New(cfg, client.Options{})
399399
Expect(err).NotTo(HaveOccurred())
@@ -405,7 +405,7 @@ var _ = Describe("Client", func() {
405405

406406
By("updating the status of Deployment")
407407
dep.Status.Replicas = 1
408-
err = cl.UpdateStatus(context.TODO(), dep)
408+
err = cl.Status().Update(context.TODO(), dep)
409409
Expect(err).NotTo(HaveOccurred())
410410

411411
By("validating updated Deployment has new status")
@@ -430,7 +430,7 @@ var _ = Describe("Client", func() {
430430
var rc int32 = 1
431431
dep.Status.Replicas = 1
432432
dep.Spec.Replicas = &rc
433-
err = cl.UpdateStatus(context.TODO(), dep)
433+
err = cl.Status().Update(context.TODO(), dep)
434434
Expect(err).NotTo(HaveOccurred())
435435

436436
By("validating updated Deployment has new status and unchanged spec")
@@ -453,7 +453,7 @@ var _ = Describe("Client", func() {
453453

454454
By("updating status of the object")
455455
node.Status.Phase = corev1.NodeRunning
456-
err = cl.UpdateStatus(context.TODO(), node)
456+
err = cl.Status().Update(context.TODO(), node)
457457
Expect(err).NotTo(HaveOccurred())
458458

459459
By("validate updated Node had new annotation")
@@ -471,7 +471,7 @@ var _ = Describe("Client", func() {
471471
Expect(cl).NotTo(BeNil())
472472

473473
By("updating status of a non-existent object")
474-
err = cl.UpdateStatus(context.TODO(), dep)
474+
err = cl.Status().Update(context.TODO(), dep)
475475
Expect(err).To(HaveOccurred())
476476

477477
close(done)
@@ -498,7 +498,7 @@ var _ = Describe("Client", func() {
498498

499499
By("updating status of the Deployment")
500500
dep.Status.Replicas = 1
501-
err = cl.UpdateStatus(context.TODO(), dep)
501+
err = cl.Status().Update(context.TODO(), dep)
502502
Expect(err).To(HaveOccurred())
503503
Expect(err.Error()).To(ContainSubstring("no kind is registered for the type"))
504504

pkg/client/fake/client.go

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -123,10 +123,8 @@ func (c *fakeClient) Update(ctx context.Context, obj runtime.Object) error {
123123
return c.tracker.Update(gvr, obj, accessor.GetNamespace())
124124
}
125125

126-
func (c *fakeClient) UpdateStatus(ctx context.Context, obj runtime.Object) error {
127-
// TODO(droot): This results in full update of the obj (spec + status). Need
128-
// a way to update status field only.
129-
return c.Update(ctx, obj)
126+
func (c *fakeClient) Status() client.StatusWriter {
127+
return &fakeStatusWriter{client: c}
130128
}
131129

132130
func getGVRFromObject(obj runtime.Object) (schema.GroupVersionResource, error) {
@@ -137,3 +135,13 @@ func getGVRFromObject(obj runtime.Object) (schema.GroupVersionResource, error) {
137135
gvr, _ := meta.UnsafeGuessKindToResource(gvk)
138136
return gvr, nil
139137
}
138+
139+
type fakeStatusWriter struct {
140+
client *fakeClient
141+
}
142+
143+
func (sw *fakeStatusWriter) Update(ctx context.Context, obj runtime.Object) error {
144+
// TODO(droot): This results in full update of the obj (spec + status). Need
145+
// a way to update status field only.
146+
return sw.client.Update(ctx, obj)
147+
}

pkg/client/interfaces.go

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,17 +55,27 @@ type Writer interface {
5555
// Update updates the given obj in the Kubernetes cluster. obj must be a
5656
// struct pointer so that obj can be updated with the content returned by the Server.
5757
Update(ctx context.Context, obj runtime.Object) error
58+
}
59+
60+
// StatusClient knows how to create a client which can update status subresource
61+
// for kubernetes objects.
62+
type StatusClient interface {
63+
Status() StatusWriter
64+
}
5865

59-
// UpdateStatus updates the fields corresponding to status subresource for
60-
// the given obj. obj must be a struct pointer so that obj can be updated
66+
// StatusWriter knows how to update status subresource of a Kubernetes object.
67+
type StatusWriter interface {
68+
// Update updates the fields corresponding to the status subresource for the
69+
// given obj. obj must be a struct pointer so that obj can be updated
6170
// with the content returned by the Server.
62-
UpdateStatus(ctx context.Context, obj runtime.Object) error
71+
Update(ctx context.Context, obj runtime.Object) error
6372
}
6473

6574
// Client knows how to perform CRUD operations on Kubernetes objects.
6675
type Client interface {
6776
Reader
6877
Writer
78+
StatusClient
6979
}
7080

7181
// IndexerFunc knows how to take an object and turn it into a series

pkg/client/split.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,10 @@ limitations under the License.
1717
package client
1818

1919
// DelegatingClient forms an interface Client by composing separate
20-
// read and write interfaces. This way, you can have an Client that
20+
// reader, writer and statusclient interfaces. This way, you can have an Client that
2121
// reads from a cache and writes to the API server.
2222
type DelegatingClient struct {
2323
Reader
2424
Writer
25+
StatusClient
2526
}

pkg/manager/manager.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,6 @@ func New(config *rest.Config, options Options) (Manager, error) {
132132
cache, err := options.newCache(config, cache.Options{Scheme: options.Scheme, Mapper: mapper, Resync: options.SyncPeriod})
133133
if err != nil {
134134
return nil, err
135-
136135
}
137136
// Create the recorder provider to inject event recorders for the components.
138137
recorderProvider, err := options.newRecorderProvider(config, options.Scheme)
@@ -146,7 +145,7 @@ func New(config *rest.Config, options Options) (Manager, error) {
146145
errChan: make(chan error),
147146
cache: cache,
148147
fieldIndexes: cache,
149-
client: client.DelegatingClient{Reader: cache, Writer: writeObj},
148+
client: client.DelegatingClient{Reader: cache, Writer: writeObj, StatusClient: writeObj},
150149
recorderProvider: recorderProvider,
151150
}, nil
152151
}

0 commit comments

Comments
 (0)