Skip to content

Commit 59da519

Browse files
committed
fixup! Add server-side apply patch support
1 parent 42a8650 commit 59da519

File tree

5 files changed

+78
-0
lines changed

5 files changed

+78
-0
lines changed

pkg/client/client.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,3 +178,11 @@ func (sw *statusWriter) Update(ctx context.Context, obj runtime.Object) error {
178178
}
179179
return sw.client.typedClient.UpdateStatus(ctx, obj)
180180
}
181+
182+
func (sw *statusWriter) Patch(ctx context.Context, obj runtime.Object, patch Patch, opts ...PatchOptionFunc) error {
183+
_, ok := obj.(*unstructured.Unstructured)
184+
if ok {
185+
return sw.client.unstructuredClient.PatchStatus(ctx, obj, patch, opts...)
186+
}
187+
return sw.client.typedClient.PatchStatus(ctx, obj, patch, opts...)
188+
}

pkg/client/interfaces.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,17 @@ type StatusClient interface {
8686

8787
// StatusWriter knows how to update status subresource of a Kubernetes object.
8888
type StatusWriter interface {
89+
// TODO(directxman12): add update options to this
90+
8991
// Update updates the fields corresponding to the status subresource for the
9092
// given obj. obj must be a struct pointer so that obj can be updated
9193
// with the content returned by the Server.
9294
Update(ctx context.Context, obj runtime.Object) error
95+
96+
// Patch patches the given object's subresource. obj must be a struct
97+
// pointer so that obj can be updated with the content returned by the
98+
// Server.
99+
Patch(ctx context.Context, obj runtime.Object, patch Patch, opts ...PatchOptionFunc) error
93100
}
94101

95102
// Client knows how to perform CRUD operations on Kubernetes objects.

pkg/client/options.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,10 @@ type PatchOptions struct {
355355
// It's probably what controllers want to do.
356356
Force *bool
357357

358+
// FieldManager is the name of the user or component submitting
359+
// this request. It must be set with server-side apply.
360+
FieldManager string
361+
358362
// Raw represets raw patch options, passed directly to the server.
359363
Raw *metav1.PatchOptions
360364
}
@@ -378,6 +382,7 @@ func (o *PatchOptions) AsPatchOptions() *metav1.PatchOptions {
378382

379383
o.Raw.DryRun = o.DryRun
380384
o.Raw.Force = o.Force
385+
o.Raw.FieldManager = o.FieldManager
381386
return o.Raw
382387
}
383388

@@ -400,3 +405,10 @@ var ForceOwnership PatchOptionFunc = func(opts *PatchOptions) {
400405
var PatchDryRunAll PatchOptionFunc = func(opts *PatchOptions) {
401406
opts.DryRun = []string{metav1.DryRunAll}
402407
}
408+
409+
// FieldManager set the field manager name for the given server-side apply patch.
410+
func FieldManager(name string) PatchOptionFunc {
411+
return func(opts *PatchOptions) {
412+
opts.FieldManager = name
413+
}
414+
}

pkg/client/typed_client.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,3 +161,28 @@ func (c *typedClient) UpdateStatus(ctx context.Context, obj runtime.Object) erro
161161
Do().
162162
Into(obj)
163163
}
164+
165+
// PatchStatus used by StatusWriter to write status.
166+
func (c *typedClient) PatchStatus(ctx context.Context, obj runtime.Object, patch Patch, opts ...PatchOptionFunc) error {
167+
o, err := c.cache.getObjMeta(obj)
168+
if err != nil {
169+
return err
170+
}
171+
172+
data, err := patch.Data(obj)
173+
if err != nil {
174+
return err
175+
}
176+
177+
patchOpts := &PatchOptions{}
178+
return o.Patch(patch.Type()).
179+
NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()).
180+
Resource(o.resource()).
181+
Name(o.GetName()).
182+
SubResource("status").
183+
VersionedParams(patchOpts.ApplyOptions(opts).AsPatchOptions(), c.paramCodec).
184+
Body(data).
185+
Context(ctx).
186+
Do().
187+
Into(obj)
188+
}

pkg/client/unstructured_client.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ import (
2929
"k8s.io/client-go/dynamic"
3030
)
3131

32+
// TODO(directxman12): respect context in unstructured
33+
3234
// client is a client.Client that reads and writes directly from/to an API server. It lazily initializes
3335
// new clients at the time they are used, and caches the client.
3436
type unstructuredClient struct {
@@ -177,6 +179,30 @@ func (uc *unstructuredClient) UpdateStatus(_ context.Context, obj runtime.Object
177179
return nil
178180
}
179181

182+
func (uc *unstructuredClient) PatchStatus(_ context.Context, obj runtime.Object, patch Patch, opts ...PatchOptionFunc) error {
183+
u, ok := obj.(*unstructured.Unstructured)
184+
if !ok {
185+
return fmt.Errorf("unstructured client did not understand object: %T", obj)
186+
}
187+
r, err := uc.getResourceInterface(u.GroupVersionKind(), u.GetNamespace())
188+
if err != nil {
189+
return err
190+
}
191+
192+
data, err := patch.Data(obj)
193+
if err != nil {
194+
return err
195+
}
196+
197+
patchOpts := &PatchOptions{}
198+
i, err := r.Patch(u.GetName(), patch.Type(), data, *patchOpts.ApplyOptions(opts).AsPatchOptions(), "status")
199+
if err != nil {
200+
return err
201+
}
202+
u.Object = i.Object
203+
return nil
204+
}
205+
180206
func (uc *unstructuredClient) getResourceInterface(gvk schema.GroupVersionKind, ns string) (dynamic.ResourceInterface, error) {
181207
mapping, err := uc.restMapper.RESTMapping(gvk.GroupKind(), gvk.Version)
182208
if err != nil {

0 commit comments

Comments
 (0)