Allow webhook implementations to optionally disallow unknown fields. (#338)

Related: https://github.com/knative/serving/issues/3309
This commit is contained in:
Matt Moore 2019-03-25 17:52:49 -07:00 committed by Knative Prow Robot
parent fe25685384
commit 04154dda9a
2 changed files with 36 additions and 2 deletions

View File

@ -120,6 +120,8 @@ type AdmissionController struct {
Options ControllerOptions Options ControllerOptions
Handlers map[schema.GroupVersionKind]GenericCRD Handlers map[schema.GroupVersionKind]GenericCRD
Logger *zap.SugaredLogger Logger *zap.SugaredLogger
DisallowUnknownFields bool
} }
// GenericCRD is the interface definition that allows us to perform the generic // GenericCRD is the interface definition that allows us to perform the generic
@ -527,6 +529,9 @@ func (ac *AdmissionController) mutate(ctx context.Context, req *admissionv1beta1
if len(newBytes) != 0 { if len(newBytes) != 0 {
newObj = handler.DeepCopyObject().(GenericCRD) newObj = handler.DeepCopyObject().(GenericCRD)
newDecoder := json.NewDecoder(bytes.NewBuffer(newBytes)) newDecoder := json.NewDecoder(bytes.NewBuffer(newBytes))
if ac.DisallowUnknownFields {
newDecoder.DisallowUnknownFields()
}
if err := newDecoder.Decode(&newObj); err != nil { if err := newDecoder.Decode(&newObj); err != nil {
return nil, fmt.Errorf("cannot decode incoming new object: %v", err) return nil, fmt.Errorf("cannot decode incoming new object: %v", err)
} }
@ -534,6 +539,9 @@ func (ac *AdmissionController) mutate(ctx context.Context, req *admissionv1beta1
if len(oldBytes) != 0 { if len(oldBytes) != 0 {
oldObj = handler.DeepCopyObject().(GenericCRD) oldObj = handler.DeepCopyObject().(GenericCRD)
oldDecoder := json.NewDecoder(bytes.NewBuffer(oldBytes)) oldDecoder := json.NewDecoder(bytes.NewBuffer(oldBytes))
if ac.DisallowUnknownFields {
oldDecoder.DisallowUnknownFields()
}
if err := oldDecoder.Decode(&oldObj); err != nil { if err := oldDecoder.Decode(&oldObj); err != nil {
return nil, fmt.Errorf("cannot decode incoming old object: %v", err) return nil, fmt.Errorf("cannot decode incoming old object: %v", err)
} }

View File

@ -135,6 +135,31 @@ func TestUnknownVersionFails(t *testing.T) {
expectFailsWith(t, ac.admit(TestContextWithLogger(t), req), "unhandled kind") expectFailsWith(t, ac.admit(TestContextWithLogger(t), req), "unhandled kind")
} }
func TestUnknownFieldFails(t *testing.T) {
_, ac := newNonRunningTestAdmissionController(t, newDefaultOptions())
req := &admissionv1beta1.AdmissionRequest{
Operation: admissionv1beta1.Create,
Kind: metav1.GroupVersionKind{
Group: "pkg.knative.dev",
Version: "v1alpha1",
Kind: "Resource",
},
}
marshaled, err := json.Marshal(map[string]interface{}{
"spec": map[string]interface{}{
"foo": "bar",
},
})
if err != nil {
panic("failed to marshal resource")
}
req.Object.Raw = marshaled
expectFailsWith(t, ac.admit(TestContextWithLogger(t), req),
`mutation failed: cannot decode incoming new object: json: unknown field "foo"`)
}
func TestValidCreateResourceSucceeds(t *testing.T) { func TestValidCreateResourceSucceeds(t *testing.T) {
r := createResource("a name") r := createResource("a name")
for _, v := range []string{"v1alpha1", "v1beta1"} { for _, v := range []string{"v1alpha1", "v1beta1"} {
@ -701,6 +726,7 @@ func NewAdmissionController(client kubernetes.Interface, options ControllerOptio
return &AdmissionController{ return &AdmissionController{
Client: client, Client: client,
Options: options, Options: options,
DisallowUnknownFields: true,
// Use different versions and domains, for coverage. // Use different versions and domains, for coverage.
Handlers: map[schema.GroupVersionKind]GenericCRD{ Handlers: map[schema.GroupVersionKind]GenericCRD{
{ {