Skip to content

Commit 03edfd3

Browse files
committed
Support subresource modification
1 parent 196828e commit 03edfd3

File tree

10 files changed

+101
-70
lines changed

10 files changed

+101
-70
lines changed

pkg/client/client.go

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -289,40 +289,45 @@ func (c *client) List(ctx context.Context, obj ObjectList, opts ...ListOption) e
289289
}
290290

291291
// Status implements client.StatusClient.
292-
func (c *client) Status() StatusWriter {
293-
return &statusWriter{client: c}
292+
func (c *client) Status() SubResourceWriter {
293+
return &subResourceWriter{client: c, subResource: "status"}
294294
}
295295

296-
// statusWriter is client.StatusWriter that writes status subresource.
297-
type statusWriter struct {
298-
client *client
296+
func (c *client) SubResource(subResource string) SubResourceWriter {
297+
return &subResourceWriter{client: c, subResource: subResource}
299298
}
300299

301-
// ensure statusWriter implements client.StatusWriter.
302-
var _ StatusWriter = &statusWriter{}
300+
// subResourceWriter is client.SubResourceWriter that writes to subresources.
301+
type subResourceWriter struct {
302+
client *client
303+
subResource string
304+
}
305+
306+
// ensure subResourceWriter implements client.SubResourceWriter.
307+
var _ SubResourceWriter = &subResourceWriter{}
303308

304-
// Update implements client.StatusWriter.
305-
func (sw *statusWriter) Update(ctx context.Context, obj Object, opts ...UpdateOption) error {
309+
// Update implements client.SubResourceWriter.
310+
func (sw *subResourceWriter) Update(ctx context.Context, obj Object, opts ...UpdateOption) error {
306311
defer sw.client.resetGroupVersionKind(obj, obj.GetObjectKind().GroupVersionKind())
307312
switch obj.(type) {
308313
case *unstructured.Unstructured:
309-
return sw.client.unstructuredClient.UpdateStatus(ctx, obj, opts...)
314+
return sw.client.unstructuredClient.UpdateSubResource(ctx, obj, sw.subResource, opts...)
310315
case *metav1.PartialObjectMetadata:
311316
return fmt.Errorf("cannot update status using only metadata -- did you mean to patch?")
312317
default:
313-
return sw.client.typedClient.UpdateStatus(ctx, obj, opts...)
318+
return sw.client.typedClient.UpdateSubResource(ctx, obj, sw.subResource, opts...)
314319
}
315320
}
316321

317-
// Patch implements client.Client.
318-
func (sw *statusWriter) Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error {
322+
// Patch implements client.SubResourceWriter.
323+
func (sw *subResourceWriter) Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error {
319324
defer sw.client.resetGroupVersionKind(obj, obj.GetObjectKind().GroupVersionKind())
320325
switch obj.(type) {
321326
case *unstructured.Unstructured:
322-
return sw.client.unstructuredClient.PatchStatus(ctx, obj, patch, opts...)
327+
return sw.client.unstructuredClient.PatchSubResource(ctx, obj, sw.subResource, patch, opts...)
323328
case *metav1.PartialObjectMetadata:
324-
return sw.client.metadataClient.PatchStatus(ctx, obj, patch, opts...)
329+
return sw.client.metadataClient.PatchSubResource(ctx, obj, sw.subResource, patch, opts...)
325330
default:
326-
return sw.client.typedClient.PatchStatus(ctx, obj, patch, opts...)
331+
return sw.client.typedClient.PatchSubResource(ctx, obj, sw.subResource, patch, opts...)
327332
}
328333
}

pkg/client/dryrun.go

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -82,25 +82,30 @@ func (c *dryRunClient) List(ctx context.Context, obj ObjectList, opts ...ListOpt
8282
}
8383

8484
// Status implements client.StatusClient.
85-
func (c *dryRunClient) Status() StatusWriter {
86-
return &dryRunStatusWriter{client: c.client.Status()}
85+
func (c *dryRunClient) Status() SubResourceWriter {
86+
return &dryRunSubResourceWriter{client: c.client.SubResource("status")}
8787
}
8888

89-
// ensure dryRunStatusWriter implements client.StatusWriter.
90-
var _ StatusWriter = &dryRunStatusWriter{}
89+
// SubResource implements client.SubResourceClient.
90+
func (c *dryRunClient) SubResource(subResource string) SubResourceWriter {
91+
return &dryRunSubResourceWriter{client: c.client.SubResource(subResource)}
92+
}
93+
94+
// ensure dryRunSubResourceWriter implements client.SubResourceWriter.
95+
var _ SubResourceWriter = &dryRunSubResourceWriter{}
9196

92-
// dryRunStatusWriter is client.StatusWriter that writes status subresource with dryRun mode
97+
// dryRunSubResourceWriter is client.SubResourceWriter that writes status subresource with dryRun mode
9398
// enforced.
94-
type dryRunStatusWriter struct {
95-
client StatusWriter
99+
type dryRunSubResourceWriter struct {
100+
client SubResourceWriter
96101
}
97102

98-
// Update implements client.StatusWriter.
99-
func (sw *dryRunStatusWriter) Update(ctx context.Context, obj Object, opts ...UpdateOption) error {
103+
// Update implements client.SubResourceWriter.
104+
func (sw *dryRunSubResourceWriter) Update(ctx context.Context, obj Object, opts ...UpdateOption) error {
100105
return sw.client.Update(ctx, obj, append(opts, DryRunAll)...)
101106
}
102107

103-
// Patch implements client.StatusWriter.
104-
func (sw *dryRunStatusWriter) Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error {
108+
// Patch implements client.SubResourceWriter.
109+
func (sw *dryRunSubResourceWriter) Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error {
105110
return sw.client.Patch(ctx, obj, patch, append(opts, DryRunAll)...)
106111
}

pkg/client/fake/client.go

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -634,8 +634,12 @@ func (c *fakeClient) Patch(ctx context.Context, obj client.Object, patch client.
634634
return err
635635
}
636636

637-
func (c *fakeClient) Status() client.StatusWriter {
638-
return &fakeStatusWriter{client: c}
637+
func (c *fakeClient) Status() client.SubResourceWriter {
638+
return &fakeSubResourceWriter{client: c}
639+
}
640+
641+
func (c *fakeClient) SubResource(subResource string) client.SubResourceWriter {
642+
return &fakeSubResourceWriter{client: c}
639643
}
640644

641645
func (c *fakeClient) deleteObject(gvr schema.GroupVersionResource, accessor metav1.Object) error {
@@ -664,19 +668,19 @@ func getGVRFromObject(obj runtime.Object, scheme *runtime.Scheme) (schema.GroupV
664668
return gvr, nil
665669
}
666670

667-
type fakeStatusWriter struct {
671+
type fakeSubResourceWriter struct {
668672
client *fakeClient
669673
}
670674

671-
func (sw *fakeStatusWriter) Update(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
672-
// TODO(droot): This results in full update of the obj (spec + status). Need
673-
// a way to update status field only.
675+
func (sw *fakeSubResourceWriter) Update(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
676+
// TODO(droot): This results in full update of the obj (spec + subresources). Need
677+
// a way to update subresource only.
674678
return sw.client.Update(ctx, obj, opts...)
675679
}
676680

677-
func (sw *fakeStatusWriter) Patch(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption) error {
678-
// TODO(droot): This results in full update of the obj (spec + status). Need
679-
// a way to update status field only.
681+
func (sw *fakeSubResourceWriter) Patch(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption) error {
682+
// TODO(droot): This results in full update of the obj (spec + subresources). Need
683+
// a way to update subresource only.
680684
return sw.client.Patch(ctx, obj, patch, opts...)
681685
}
682686

pkg/client/interfaces.go

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,11 +81,20 @@ type Writer interface {
8181
// StatusClient knows how to create a client which can update status subresource
8282
// for kubernetes objects.
8383
type StatusClient interface {
84-
Status() StatusWriter
84+
Status() SubResourceWriter
8585
}
8686

87-
// StatusWriter knows how to update status subresource of a Kubernetes object.
88-
type StatusWriter interface {
87+
// SubResourceClient knows how to create a client which can update subresource
88+
// for kubernetes objects.
89+
type SubResourceClient interface {
90+
SubResource(subResource string) SubResourceWriter
91+
}
92+
93+
// StatusWriter is kept for backward compatibility.
94+
type StatusWriter = SubResourceWriter
95+
96+
// SubResourceWriter knows how to update subresource of a Kubernetes object.
97+
type SubResourceWriter interface {
8998
// Update updates the fields corresponding to the status subresource for the
9099
// given obj. obj must be a struct pointer so that obj can be updated
91100
// with the content returned by the Server.
@@ -102,6 +111,7 @@ type Client interface {
102111
Reader
103112
Writer
104113
StatusClient
114+
SubResourceClient
105115

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

pkg/client/metadata_client.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ func (mc *metadataClient) List(ctx context.Context, obj ObjectList, opts ...List
165165
return nil
166166
}
167167

168-
func (mc *metadataClient) PatchStatus(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error {
168+
func (mc *metadataClient) PatchSubResource(ctx context.Context, obj Object, subResource string, patch Patch, opts ...PatchOption) error {
169169
metadata, ok := obj.(*metav1.PartialObjectMetadata)
170170
if !ok {
171171
return fmt.Errorf("metadata client did not understand object: %T", obj)
@@ -183,7 +183,7 @@ func (mc *metadataClient) PatchStatus(ctx context.Context, obj Object, patch Pat
183183
}
184184

185185
patchOpts := &PatchOptions{}
186-
res, err := resInt.Patch(ctx, metadata.Name, patch.Type(), data, *patchOpts.AsPatchOptions(), "status")
186+
res, err := resInt.Patch(ctx, metadata.Name, patch.Type(), data, *patchOpts.AsPatchOptions(), subResource)
187187
if err != nil {
188188
return err
189189
}

pkg/client/namespaced_client.go

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -161,21 +161,26 @@ func (n *namespacedClient) List(ctx context.Context, obj ObjectList, opts ...Lis
161161
}
162162

163163
// Status implements client.StatusClient.
164-
func (n *namespacedClient) Status() StatusWriter {
165-
return &namespacedClientStatusWriter{StatusClient: n.client.Status(), namespace: n.namespace, namespacedclient: n}
164+
func (n *namespacedClient) Status() SubResourceWriter {
165+
return &namespacedClientSubResourceWriter{StatusClient: n.client.SubResource("status"), namespace: n.namespace, namespacedclient: n}
166166
}
167167

168-
// ensure namespacedClientStatusWriter implements client.StatusWriter.
169-
var _ StatusWriter = &namespacedClientStatusWriter{}
168+
// SubResource implements client.SubResourceClient.
169+
func (n *namespacedClient) SubResource(subResource string) SubResourceWriter {
170+
return &namespacedClientSubResourceWriter{StatusClient: n.client.SubResource(subResource), namespace: n.namespace, namespacedclient: n}
171+
}
172+
173+
// ensure namespacedClientSubResourceWriter implements client.SubResourceWriter.
174+
var _ SubResourceWriter = &namespacedClientSubResourceWriter{}
170175

171-
type namespacedClientStatusWriter struct {
172-
StatusClient StatusWriter
176+
type namespacedClientSubResourceWriter struct {
177+
StatusClient SubResourceWriter
173178
namespace string
174179
namespacedclient Client
175180
}
176181

177-
// Update implements client.StatusWriter.
178-
func (nsw *namespacedClientStatusWriter) Update(ctx context.Context, obj Object, opts ...UpdateOption) error {
182+
// Update implements client.SubResourceWriter.
183+
func (nsw *namespacedClientSubResourceWriter) Update(ctx context.Context, obj Object, opts ...UpdateOption) error {
179184
isNamespaceScoped, err := objectutil.IsAPINamespaced(obj, nsw.namespacedclient.Scheme(), nsw.namespacedclient.RESTMapper())
180185

181186
if err != nil {
@@ -193,8 +198,8 @@ func (nsw *namespacedClientStatusWriter) Update(ctx context.Context, obj Object,
193198
return nsw.StatusClient.Update(ctx, obj, opts...)
194199
}
195200

196-
// Patch implements client.StatusWriter.
197-
func (nsw *namespacedClientStatusWriter) Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error {
201+
// Patch implements client.SubResourceWriter.
202+
func (nsw *namespacedClientSubResourceWriter) Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error {
198203
isNamespaceScoped, err := objectutil.IsAPINamespaced(obj, nsw.namespacedclient.Scheme(), nsw.namespacedclient.RESTMapper())
199204

200205
if err != nil {

pkg/client/namespaced_client_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -480,7 +480,7 @@ var _ = Describe("NamespacedClient", func() {
480480
})
481481
})
482482

483-
Describe("StatusWriter", func() {
483+
Describe("SubResourceWriter", func() {
484484
var err error
485485
BeforeEach(func() {
486486
dep, err = clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
@@ -495,7 +495,7 @@ var _ = Describe("NamespacedClient", func() {
495495
changedDep := dep.DeepCopy()
496496
changedDep.Status.Replicas = 99
497497

498-
Expect(getClient().Status().Update(ctx, changedDep)).NotTo(HaveOccurred())
498+
Expect(getClient().SubResource("status").Update(ctx, changedDep)).NotTo(HaveOccurred())
499499

500500
actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
501501
Expect(err).NotTo(HaveOccurred())
@@ -509,14 +509,14 @@ var _ = Describe("NamespacedClient", func() {
509509
changedDep.SetNamespace("test")
510510
changedDep.Status.Replicas = 99
511511

512-
Expect(getClient().Status().Update(ctx, changedDep)).To(HaveOccurred())
512+
Expect(getClient().SubResource("status").Update(ctx, changedDep)).To(HaveOccurred())
513513
})
514514

515515
It("should change objects via status patch", func() {
516516
changedDep := dep.DeepCopy()
517517
changedDep.Status.Replicas = 99
518518

519-
Expect(getClient().Status().Patch(ctx, changedDep, client.MergeFrom(dep))).NotTo(HaveOccurred())
519+
Expect(getClient().SubResource("status").Patch(ctx, changedDep, client.MergeFrom(dep))).NotTo(HaveOccurred())
520520

521521
actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
522522
Expect(err).NotTo(HaveOccurred())
@@ -530,7 +530,7 @@ var _ = Describe("NamespacedClient", func() {
530530
changedDep.Status.Replicas = 99
531531
changedDep.SetNamespace("test")
532532

533-
Expect(getClient().Status().Patch(ctx, changedDep, client.MergeFrom(dep))).To(HaveOccurred())
533+
Expect(getClient().SubResource("status").Patch(ctx, changedDep, client.MergeFrom(dep))).To(HaveOccurred())
534534
})
535535
})
536536

pkg/client/split.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,15 +61,17 @@ func NewDelegatingClient(in NewDelegatingClientInput) (Client, error) {
6161
uncachedGVKs: uncachedGVKs,
6262
cacheUnstructured: in.CacheUnstructured,
6363
},
64-
Writer: in.Client,
65-
StatusClient: in.Client,
64+
Writer: in.Client,
65+
StatusClient: in.Client,
66+
SubResourceClient: in.Client,
6667
}, nil
6768
}
6869

6970
type delegatingClient struct {
7071
Reader
7172
Writer
7273
StatusClient
74+
SubResourceClient
7375

7476
scheme *runtime.Scheme
7577
mapper meta.RESTMapper

pkg/client/typed_client.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import (
2424

2525
var _ Reader = &typedClient{}
2626
var _ Writer = &typedClient{}
27-
var _ StatusWriter = &typedClient{}
27+
var _ SubResourceWriter = &typedClient{}
2828

2929
// client is a client.Client that reads and writes directly from/to an API server. It lazily initializes
3030
// new clients at the time they are used, and caches the client.
@@ -159,8 +159,8 @@ func (c *typedClient) List(ctx context.Context, obj ObjectList, opts ...ListOpti
159159
Into(obj)
160160
}
161161

162-
// UpdateStatus used by StatusWriter to write status.
163-
func (c *typedClient) UpdateStatus(ctx context.Context, obj Object, opts ...UpdateOption) error {
162+
// UpdateSubResource used by SubResourceWriter to write status.
163+
func (c *typedClient) UpdateSubResource(ctx context.Context, obj Object, subResource string, opts ...UpdateOption) error {
164164
o, err := c.cache.getObjMeta(obj)
165165
if err != nil {
166166
return err
@@ -173,15 +173,15 @@ func (c *typedClient) UpdateStatus(ctx context.Context, obj Object, opts ...Upda
173173
NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()).
174174
Resource(o.resource()).
175175
Name(o.GetName()).
176-
SubResource("status").
176+
SubResource(subResource).
177177
Body(obj).
178178
VersionedParams((&UpdateOptions{}).ApplyOptions(opts).AsUpdateOptions(), c.paramCodec).
179179
Do(ctx).
180180
Into(obj)
181181
}
182182

183-
// PatchStatus used by StatusWriter to write status.
184-
func (c *typedClient) PatchStatus(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error {
183+
// PatchSubResource used by SubResourceWriter to write subresource.
184+
func (c *typedClient) PatchSubResource(ctx context.Context, obj Object, subResource string, patch Patch, opts ...PatchOption) error {
185185
o, err := c.cache.getObjMeta(obj)
186186
if err != nil {
187187
return err
@@ -197,7 +197,7 @@ func (c *typedClient) PatchStatus(ctx context.Context, obj Object, patch Patch,
197197
NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()).
198198
Resource(o.resource()).
199199
Name(o.GetName()).
200-
SubResource("status").
200+
SubResource(subResource).
201201
Body(data).
202202
VersionedParams(patchOpts.ApplyOptions(opts).AsPatchOptions(), c.paramCodec).
203203
Do(ctx).

pkg/client/unstructured_client.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import (
2727

2828
var _ Reader = &unstructuredClient{}
2929
var _ Writer = &unstructuredClient{}
30-
var _ StatusWriter = &unstructuredClient{}
30+
var _ SubResourceWriter = &unstructuredClient{}
3131

3232
// client is a client.Client that reads and writes directly from/to an API server. It lazily initializes
3333
// new clients at the time they are used, and caches the client.
@@ -216,7 +216,7 @@ func (uc *unstructuredClient) List(ctx context.Context, obj ObjectList, opts ...
216216
Into(obj)
217217
}
218218

219-
func (uc *unstructuredClient) UpdateStatus(ctx context.Context, obj Object, opts ...UpdateOption) error {
219+
func (uc *unstructuredClient) UpdateSubResource(ctx context.Context, obj Object, subResource string, opts ...UpdateOption) error {
220220
if _, ok := obj.(*unstructured.Unstructured); !ok {
221221
return fmt.Errorf("unstructured client did not understand object: %T", obj)
222222
}
@@ -230,14 +230,14 @@ func (uc *unstructuredClient) UpdateStatus(ctx context.Context, obj Object, opts
230230
NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()).
231231
Resource(o.resource()).
232232
Name(o.GetName()).
233-
SubResource("status").
233+
SubResource(subResource).
234234
Body(obj).
235235
VersionedParams((&UpdateOptions{}).ApplyOptions(opts).AsUpdateOptions(), uc.paramCodec).
236236
Do(ctx).
237237
Into(obj)
238238
}
239239

240-
func (uc *unstructuredClient) PatchStatus(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error {
240+
func (uc *unstructuredClient) PatchSubResource(ctx context.Context, obj Object, subResource string, patch Patch, opts ...PatchOption) error {
241241
u, ok := obj.(*unstructured.Unstructured)
242242
if !ok {
243243
return fmt.Errorf("unstructured client did not understand object: %T", obj)
@@ -260,7 +260,7 @@ func (uc *unstructuredClient) PatchStatus(ctx context.Context, obj Object, patch
260260
NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()).
261261
Resource(o.resource()).
262262
Name(o.GetName()).
263-
SubResource("status").
263+
SubResource(subResource).
264264
Body(data).
265265
VersionedParams(patchOpts.ApplyOptions(opts).AsPatchOptions(), uc.paramCodec).
266266
Do(ctx).

0 commit comments

Comments
 (0)