Skip to content

Commit cd1f7a6

Browse files
committed
Support update patch options
This supports passing update options to patch options (e.g. dry-run options).
1 parent b002d31 commit cd1f7a6

File tree

6 files changed

+78
-3
lines changed

6 files changed

+78
-3
lines changed

pkg/client/client_test.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1062,6 +1062,27 @@ var _ = Describe("Client", func() {
10621062
PIt("should fail if the GVK cannot be mapped to a Resource", func() {
10631063

10641064
})
1065+
1066+
It("should respect passed in update options", func() {
1067+
By("creating a new client")
1068+
cl, err := client.New(cfg, client.Options{})
1069+
Expect(err).NotTo(HaveOccurred())
1070+
Expect(cl).NotTo(BeNil())
1071+
1072+
By("initially creating a Deployment")
1073+
dep, err := clientset.AppsV1().Deployments(ns).Create(dep)
1074+
Expect(err).NotTo(HaveOccurred())
1075+
1076+
By("patching the Deployment with dry-run")
1077+
err = cl.Patch(context.TODO(), dep, client.ConstantPatch(types.MergePatchType, mergePatch), client.UpdatePatchWith(client.UpdateDryRunAll()))
1078+
Expect(err).NotTo(HaveOccurred())
1079+
1080+
By("validating patched Deployment doesn't have the new annotation")
1081+
actual, err := clientset.AppsV1().Deployments(ns).Get(dep.Name, metav1.GetOptions{})
1082+
Expect(err).NotTo(HaveOccurred())
1083+
Expect(actual).NotTo(BeNil())
1084+
Expect(actual.Annotations).NotTo(HaveKey("foo"))
1085+
})
10651086
})
10661087
Context("with unstructured objects", func() {
10671088
It("should patch an existing object from a go struct", func(done Done) {
@@ -1142,6 +1163,35 @@ var _ = Describe("Client", func() {
11421163

11431164
close(done)
11441165
})
1166+
1167+
It("should respect passed-in update options", func() {
1168+
By("creating a new client")
1169+
cl, err := client.New(cfg, client.Options{})
1170+
Expect(err).NotTo(HaveOccurred())
1171+
Expect(cl).NotTo(BeNil())
1172+
1173+
By("initially creating a Deployment")
1174+
dep, err := clientset.AppsV1().Deployments(ns).Create(dep)
1175+
Expect(err).NotTo(HaveOccurred())
1176+
1177+
By("patching the Deployment")
1178+
depName := dep.Name
1179+
u := &unstructured.Unstructured{}
1180+
scheme.Convert(dep, u, nil)
1181+
u.SetGroupVersionKind(schema.GroupVersionKind{
1182+
Group: "apps",
1183+
Kind: "Deployment",
1184+
Version: "v1",
1185+
})
1186+
err = cl.Patch(context.TODO(), u, client.ConstantPatch(types.MergePatchType, mergePatch), client.UpdatePatchWith(client.UpdateDryRunAll()))
1187+
Expect(err).NotTo(HaveOccurred())
1188+
1189+
By("validating patched Deployment does not have the new annotation")
1190+
actual, err := clientset.AppsV1().Deployments(ns).Get(depName, metav1.GetOptions{})
1191+
Expect(err).NotTo(HaveOccurred())
1192+
Expect(actual).NotTo(BeNil())
1193+
Expect(actual.Annotations).NotTo(HaveKey("foo"))
1194+
})
11451195
})
11461196
})
11471197

pkg/client/fake/client_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ var _ = Describe("Fake client", func() {
218218
},
219219
})
220220
Expect(err).NotTo(HaveOccurred())
221-
err = cl.Patch(nil, dep, client.ConstantPatch(types.JSONPatchType, mergePatch))
221+
err = cl.Patch(nil, dep, client.ConstantPatch(types.StrategicMergePatchType, mergePatch))
222222
Expect(err).NotTo(HaveOccurred())
223223

224224
By("Getting the patched deployment")

pkg/client/interfaces.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,9 +443,31 @@ func UpdateDryRunAll() UpdateOptionFunc {
443443

444444
// PatchOptions contains options for patch requests.
445445
type PatchOptions struct {
446+
UpdateOptions
447+
}
448+
449+
// ApplyOptions executes the given PatchOptionFuncs, mutating these PatchOptions.
450+
// It returns the mutated PatchOptions for convenience.
451+
func (o *PatchOptions) ApplyOptions(optFuncs []PatchOptionFunc) *PatchOptions {
452+
for _, optFunc := range optFuncs {
453+
optFunc(o)
454+
}
455+
return o
446456
}
447457

448458
// PatchOptionFunc is a function that mutates a PatchOptions struct. It implements
449459
// the functional options pattern. See
450460
// https://github.com/tmrts/go-patterns/blob/master/idiom/functional-options.md.
451461
type PatchOptionFunc func(*PatchOptions)
462+
463+
// Sadly, we need a separate function to "adapt" PatchOptions to the constituent
464+
// update options, since there's no way to write a function that works for both.
465+
466+
// UpdatePatchWith adapts the given UpdateOptionFuncs to be a PatchOptionFunc.
467+
func UpdatePatchWith(optFuncs ...UpdateOptionFunc) PatchOptionFunc {
468+
return func(opts *PatchOptions) {
469+
for _, optFunc := range optFuncs {
470+
optFunc(&opts.UpdateOptions)
471+
}
472+
}
473+
}

pkg/client/patch.go

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

1919
import (
20-
"github.com/evanphx/json-patch"
20+
jsonpatch "github.com/evanphx/json-patch"
2121
"k8s.io/apimachinery/pkg/runtime"
2222
"k8s.io/apimachinery/pkg/types"
2323
"k8s.io/apimachinery/pkg/util/json"

pkg/client/typed_client.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,10 +98,12 @@ func (c *typedClient) Patch(ctx context.Context, obj runtime.Object, patch Patch
9898
return err
9999
}
100100

101+
patchOpts := &PatchOptions{}
101102
return o.Patch(patch.Type()).
102103
NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()).
103104
Resource(o.resource()).
104105
Name(o.GetName()).
106+
VersionedParams(patchOpts.ApplyOptions(opts).AsUpdateOptions(), c.paramCodec).
105107
Body(data).
106108
Context(ctx).
107109
Do().

pkg/client/unstructured_client.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,8 @@ func (uc *unstructuredClient) Patch(_ context.Context, obj runtime.Object, patch
107107
return err
108108
}
109109

110-
i, err := r.Patch(u.GetName(), patch.Type(), data, metav1.UpdateOptions{})
110+
patchOpts := &PatchOptions{}
111+
i, err := r.Patch(u.GetName(), patch.Type(), data, *patchOpts.ApplyOptions(opts).AsUpdateOptions())
111112
if err != nil {
112113
return err
113114
}

0 commit comments

Comments
 (0)