Skip to content

Commit 13c4991

Browse files
alculquicondortrasc
authored andcommitted
Fix custom defaulter from deleting unknown fields
1 parent 5af6ffa commit 13c4991

File tree

2 files changed

+36
-6
lines changed

2 files changed

+36
-6
lines changed

pkg/webhook/admission/defaulter_custom.go

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -71,24 +71,32 @@ func (h *defaulterForType) Handle(ctx context.Context, req Request) Response {
7171
ctx = NewContextWithRequest(ctx, req)
7272

7373
// Get the object in the request
74-
obj := h.object.DeepCopyObject()
75-
if err := h.decoder.Decode(req, obj); err != nil {
74+
original := h.object.DeepCopyObject()
75+
if err := h.decoder.Decode(req, original); err != nil {
7676
return Errored(http.StatusBadRequest, err)
7777
}
7878

7979
// Default the object
80-
if err := h.defaulter.Default(ctx, obj); err != nil {
80+
updated := original.DeepCopyObject()
81+
if err := h.defaulter.Default(ctx, updated); err != nil {
8182
var apiStatus apierrors.APIStatus
8283
if errors.As(err, &apiStatus) {
8384
return validationResponseFromStatus(false, apiStatus.Status())
8485
}
8586
return Denied(err.Error())
8687
}
8788

88-
// Create the patch
89-
marshalled, err := json.Marshal(obj)
89+
// Create the patch.
90+
// We need to decode and marshall the original because the type registered in the
91+
// decoder might not match the latest version of the API.
92+
// Creating a diff from the raw object might cause new fields to be dropped.
93+
marshalledOriginal, err := json.Marshal(original)
9094
if err != nil {
9195
return Errored(http.StatusInternalServerError, err)
9296
}
93-
return PatchResponseFromRaw(req.Object.Raw, marshalled)
97+
marshalledUpdated, err := json.Marshal(updated)
98+
if err != nil {
99+
return Errored(http.StatusInternalServerError, err)
100+
}
101+
return PatchResponseFromRaw(marshalledOriginal, marshalledUpdated)
94102
}

pkg/webhook/admission/defaulter_custom_test.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020

2121
. "github.com/onsi/ginkgo/v2"
2222
. "github.com/onsi/gomega"
23+
"gomodules.xyz/jsonpatch/v2"
2324

2425
admissionv1 "k8s.io/api/admission/v1"
2526
"k8s.io/apimachinery/pkg/runtime"
@@ -28,6 +29,27 @@ import (
2829

2930
var _ = Describe("Defaulter Handler", func() {
3031

32+
It("should should not lose unknown fields", func() {
33+
obj := &TestDefaulter{}
34+
handler := WithCustomDefaulter(admissionScheme, obj, &TestCustomDefaulter{})
35+
36+
resp := handler.Handle(context.TODO(), Request{
37+
AdmissionRequest: admissionv1.AdmissionRequest{
38+
Operation: admissionv1.Create,
39+
Object: runtime.RawExtension{
40+
Raw: []byte(`{"newField":"foo"}`),
41+
},
42+
},
43+
})
44+
Expect(resp.Allowed).Should(BeTrue())
45+
Expect(resp.Patches).To(Equal([]jsonpatch.JsonPatchOperation{{
46+
Operation: "add",
47+
Path: "/replica",
48+
Value: 2.0,
49+
}}))
50+
Expect(resp.Result.Code).Should(Equal(int32(http.StatusOK)))
51+
})
52+
3153
It("should return ok if received delete verb in defaulter handler", func() {
3254
obj := &TestDefaulter{}
3355
handler := WithCustomDefaulter(admissionScheme, obj, &TestCustomDefaulter{})

0 commit comments

Comments
 (0)