Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

馃悰 Actually inject the scheme in StandaloneWebhook #1490

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
18 changes: 18 additions & 0 deletions pkg/webhook/admission/admissiontest/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
Copyright 2021 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// Package admissiontest contains fake webhooks for validating admission webhooks
package admissiontest
50 changes: 50 additions & 0 deletions pkg/webhook/admission/admissiontest/util.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package admissiontest

import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
)

// FakeValidator provides fake validating webhook functionality for testing
// It implements the admission.Validator interface and
// rejects all requests with the same configured error
// or passes if ErrorToReturn is nil.
type FakeValidator struct {
// ErrorToReturn is the error for which the FakeValidator rejects all requests
ErrorToReturn error `json:"ErrorToReturn,omitempty"`
// GVKToReturn is the GroupVersionKind that the webhook operates on
GVKToReturn schema.GroupVersionKind
}

// ValidateCreate implements admission.Validator
func (v *FakeValidator) ValidateCreate() error {
return v.ErrorToReturn
}

// ValidateUpdate implements admission.Validator
func (v *FakeValidator) ValidateUpdate(old runtime.Object) error {
return v.ErrorToReturn
}

// ValidateDelete implements admission.Validator
func (v *FakeValidator) ValidateDelete() error {
return v.ErrorToReturn
}

// GetObjectKind implements admission.Validator
func (v *FakeValidator) GetObjectKind() schema.ObjectKind { return v }

// DeepCopyObject implements admission.Validator
func (v *FakeValidator) DeepCopyObject() runtime.Object {
return &FakeValidator{ErrorToReturn: v.ErrorToReturn, GVKToReturn: v.GVKToReturn}
}

// GroupVersionKind implements admission.Validator
func (v *FakeValidator) GroupVersionKind() schema.GroupVersionKind {
return v.GVKToReturn
}

// SetGroupVersionKind implements admission.Validator
func (v *FakeValidator) SetGroupVersionKind(gvk schema.GroupVersionKind) {
v.GVKToReturn = gvk
}
41 changes: 6 additions & 35 deletions pkg/webhook/admission/validator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"sigs.k8s.io/controller-runtime/pkg/webhook/admission/admissiontest"

admissionv1 "k8s.io/api/admission/v1"
apierrs "k8s.io/apimachinery/pkg/api/errors"
Expand All @@ -16,13 +17,15 @@ import (
"k8s.io/client-go/kubernetes/scheme"
)

var fakeValidatorVK = schema.GroupVersionKind{Group: "foo.test.org", Version: "v1", Kind: "fakeValidator"}

var _ = Describe("validatingHandler", func() {

decoder, _ := NewDecoder(scheme.Scheme)

Context("when dealing with successful results", func() {

f := &fakeValidator{ErrorToReturn: nil}
f := &admissiontest.FakeValidator{ErrorToReturn: nil, GVKToReturn: fakeValidatorVK}
handler := validatingHandler{validator: f, decoder: decoder}

It("should return 200 in response when create succeeds", func() {
Expand Down Expand Up @@ -85,7 +88,7 @@ var _ = Describe("validatingHandler", func() {
Code: http.StatusUnprocessableEntity,
},
}
f := &fakeValidator{ErrorToReturn: expectedError}
f := &admissiontest.FakeValidator{ErrorToReturn: expectedError, GVKToReturn: fakeValidatorVK}
handler := validatingHandler{validator: f, decoder: decoder}

It("should propagate the Status from ValidateCreate's return value to the HTTP response", func() {
Expand Down Expand Up @@ -150,7 +153,7 @@ var _ = Describe("validatingHandler", func() {
Context("when dealing with non-status errors", func() {

expectedError := goerrors.New("some error")
f := &fakeValidator{ErrorToReturn: expectedError}
f := &admissiontest.FakeValidator{ErrorToReturn: expectedError, GVKToReturn: fakeValidatorVK}
handler := validatingHandler{validator: f, decoder: decoder}

It("should return 403 response when ValidateCreate with error message embedded", func() {
Expand Down Expand Up @@ -219,35 +222,3 @@ var _ = Describe("validatingHandler", func() {
PIt("should return 400 in response when delete fails on decode", func() {})

})

type fakeValidator struct {
ErrorToReturn error `json:"ErrorToReturn,omitempty"`
}

var _ Validator = &fakeValidator{}

var fakeValidatorVK = schema.GroupVersionKind{Group: "foo.test.org", Version: "v1", Kind: "fakeValidator"}

func (v *fakeValidator) ValidateCreate() error {
return v.ErrorToReturn
}

func (v *fakeValidator) ValidateUpdate(old runtime.Object) error {
return v.ErrorToReturn
}

func (v *fakeValidator) ValidateDelete() error {
return v.ErrorToReturn
}

func (v *fakeValidator) GetObjectKind() schema.ObjectKind { return v }

func (v *fakeValidator) DeepCopyObject() runtime.Object {
return &fakeValidator{ErrorToReturn: v.ErrorToReturn}
}

func (v *fakeValidator) GroupVersionKind() schema.GroupVersionKind {
return fakeValidatorVK
}

func (v *fakeValidator) SetGroupVersionKind(gvk schema.GroupVersionKind) {}
4 changes: 1 addition & 3 deletions pkg/webhook/admission/webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,9 +235,7 @@ func StandaloneWebhook(hook *Webhook, opts StandaloneOptions) (http.Handler, err
opts.Scheme = scheme.Scheme
}

var err error
hook.decoder, err = NewDecoder(opts.Scheme)
if err != nil {
if err := hook.InjectScheme(opts.Scheme); err != nil {
return nil, err
}

Expand Down
18 changes: 13 additions & 5 deletions pkg/webhook/webhook_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package webhook_test
import (
"context"
"crypto/tls"
goerrors "errors"
"fmt"
"net"
"net/http"
Expand All @@ -16,12 +17,14 @@ import (
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/kubernetes/scheme"
"sigs.k8s.io/controller-runtime/pkg/certwatcher"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/manager"
"sigs.k8s.io/controller-runtime/pkg/webhook"
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
"sigs.k8s.io/controller-runtime/pkg/webhook/admission/admissiontest"
)

var _ = Describe("Webhook", func() {
Expand Down Expand Up @@ -111,7 +114,8 @@ var _ = Describe("Webhook", func() {
Context("when running a standalone webhook", func() {
It("should reject create request for webhook that rejects all requests", func(done Done) {
ctx, cancel := context.WithCancel(context.Background())
// generate tls cfg

By("generating the TLS config")
certPath := filepath.Join(testenv.WebhookInstallOptions.LocalServingCertDir, "tls.crt")
keyPath := filepath.Join(testenv.WebhookInstallOptions.LocalServingCertDir, "tls.key")

Expand All @@ -126,18 +130,22 @@ var _ = Describe("Webhook", func() {
GetCertificate: certWatcher.GetCertificate,
}

// generate listener
By("generating the listener")
listener, err := tls.Listen("tcp",
net.JoinHostPort(testenv.WebhookInstallOptions.LocalServingHost,
strconv.Itoa(int(testenv.WebhookInstallOptions.LocalServingPort))), cfg)
Expect(err).NotTo(HaveOccurred())

// create and register the standalone webhook
hook, err := admission.StandaloneWebhook(&webhook.Admission{Handler: &rejectingValidator{}}, admission.StandaloneOptions{})
By("creating and registering the standalone webhook")
hook, err := admission.StandaloneWebhook(admission.ValidatingWebhookFor(
&admissiontest.FakeValidator{
ErrorToReturn: goerrors.New("Always denied"),
GVKToReturn: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"},
}), admission.StandaloneOptions{})
Expect(err).NotTo(HaveOccurred())
http.Handle("/failing", hook)

// run the http server
By("running the http server")
srv := &http.Server{}
go func() {
idleConnsClosed := make(chan struct{})
Expand Down