Skip to content

Commit b2c90ab

Browse files
authored
Merge pull request #1490 from kevindelgado/standalone-webhooks-fix-scheme
🐛 Actually inject the scheme in StandaloneWebhook
2 parents d5d2551 + 19168b3 commit b2c90ab

File tree

5 files changed

+88
-43
lines changed

5 files changed

+88
-43
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/*
2+
Copyright 2021 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
// Package admissiontest contains fake webhooks for validating admission webhooks
18+
package admissiontest
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package admissiontest
2+
3+
import (
4+
"k8s.io/apimachinery/pkg/runtime"
5+
"k8s.io/apimachinery/pkg/runtime/schema"
6+
)
7+
8+
// FakeValidator provides fake validating webhook functionality for testing
9+
// It implements the admission.Validator interface and
10+
// rejects all requests with the same configured error
11+
// or passes if ErrorToReturn is nil.
12+
type FakeValidator struct {
13+
// ErrorToReturn is the error for which the FakeValidator rejects all requests
14+
ErrorToReturn error `json:"ErrorToReturn,omitempty"`
15+
// GVKToReturn is the GroupVersionKind that the webhook operates on
16+
GVKToReturn schema.GroupVersionKind
17+
}
18+
19+
// ValidateCreate implements admission.Validator
20+
func (v *FakeValidator) ValidateCreate() error {
21+
return v.ErrorToReturn
22+
}
23+
24+
// ValidateUpdate implements admission.Validator
25+
func (v *FakeValidator) ValidateUpdate(old runtime.Object) error {
26+
return v.ErrorToReturn
27+
}
28+
29+
// ValidateDelete implements admission.Validator
30+
func (v *FakeValidator) ValidateDelete() error {
31+
return v.ErrorToReturn
32+
}
33+
34+
// GetObjectKind implements admission.Validator
35+
func (v *FakeValidator) GetObjectKind() schema.ObjectKind { return v }
36+
37+
// DeepCopyObject implements admission.Validator
38+
func (v *FakeValidator) DeepCopyObject() runtime.Object {
39+
return &FakeValidator{ErrorToReturn: v.ErrorToReturn, GVKToReturn: v.GVKToReturn}
40+
}
41+
42+
// GroupVersionKind implements admission.Validator
43+
func (v *FakeValidator) GroupVersionKind() schema.GroupVersionKind {
44+
return v.GVKToReturn
45+
}
46+
47+
// SetGroupVersionKind implements admission.Validator
48+
func (v *FakeValidator) SetGroupVersionKind(gvk schema.GroupVersionKind) {
49+
v.GVKToReturn = gvk
50+
}

pkg/webhook/admission/validator_test.go

Lines changed: 6 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77

88
. "github.com/onsi/ginkgo"
99
. "github.com/onsi/gomega"
10+
"sigs.k8s.io/controller-runtime/pkg/webhook/admission/admissiontest"
1011

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

20+
var fakeValidatorVK = schema.GroupVersionKind{Group: "foo.test.org", Version: "v1", Kind: "fakeValidator"}
21+
1922
var _ = Describe("validatingHandler", func() {
2023

2124
decoder, _ := NewDecoder(scheme.Scheme)
2225

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

25-
f := &fakeValidator{ErrorToReturn: nil}
28+
f := &admissiontest.FakeValidator{ErrorToReturn: nil, GVKToReturn: fakeValidatorVK}
2629
handler := validatingHandler{validator: f, decoder: decoder}
2730

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

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

152155
expectedError := goerrors.New("some error")
153-
f := &fakeValidator{ErrorToReturn: expectedError}
156+
f := &admissiontest.FakeValidator{ErrorToReturn: expectedError, GVKToReturn: fakeValidatorVK}
154157
handler := validatingHandler{validator: f, decoder: decoder}
155158

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

221224
})
222-
223-
type fakeValidator struct {
224-
ErrorToReturn error `json:"ErrorToReturn,omitempty"`
225-
}
226-
227-
var _ Validator = &fakeValidator{}
228-
229-
var fakeValidatorVK = schema.GroupVersionKind{Group: "foo.test.org", Version: "v1", Kind: "fakeValidator"}
230-
231-
func (v *fakeValidator) ValidateCreate() error {
232-
return v.ErrorToReturn
233-
}
234-
235-
func (v *fakeValidator) ValidateUpdate(old runtime.Object) error {
236-
return v.ErrorToReturn
237-
}
238-
239-
func (v *fakeValidator) ValidateDelete() error {
240-
return v.ErrorToReturn
241-
}
242-
243-
func (v *fakeValidator) GetObjectKind() schema.ObjectKind { return v }
244-
245-
func (v *fakeValidator) DeepCopyObject() runtime.Object {
246-
return &fakeValidator{ErrorToReturn: v.ErrorToReturn}
247-
}
248-
249-
func (v *fakeValidator) GroupVersionKind() schema.GroupVersionKind {
250-
return fakeValidatorVK
251-
}
252-
253-
func (v *fakeValidator) SetGroupVersionKind(gvk schema.GroupVersionKind) {}

pkg/webhook/admission/webhook.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -235,9 +235,7 @@ func StandaloneWebhook(hook *Webhook, opts StandaloneOptions) (http.Handler, err
235235
opts.Scheme = scheme.Scheme
236236
}
237237

238-
var err error
239-
hook.decoder, err = NewDecoder(opts.Scheme)
240-
if err != nil {
238+
if err := hook.InjectScheme(opts.Scheme); err != nil {
241239
return nil, err
242240
}
243241

pkg/webhook/webhook_integration_test.go

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package webhook_test
33
import (
44
"context"
55
"crypto/tls"
6+
goerrors "errors"
67
"fmt"
78
"net"
89
"net/http"
@@ -16,12 +17,14 @@ import (
1617
corev1 "k8s.io/api/core/v1"
1718
"k8s.io/apimachinery/pkg/api/errors"
1819
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
20+
"k8s.io/apimachinery/pkg/runtime/schema"
1921
"k8s.io/client-go/kubernetes/scheme"
2022
"sigs.k8s.io/controller-runtime/pkg/certwatcher"
2123
"sigs.k8s.io/controller-runtime/pkg/client"
2224
"sigs.k8s.io/controller-runtime/pkg/manager"
2325
"sigs.k8s.io/controller-runtime/pkg/webhook"
2426
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
27+
"sigs.k8s.io/controller-runtime/pkg/webhook/admission/admissiontest"
2528
)
2629

2730
var _ = Describe("Webhook", func() {
@@ -111,7 +114,8 @@ var _ = Describe("Webhook", func() {
111114
Context("when running a standalone webhook", func() {
112115
It("should reject create request for webhook that rejects all requests", func(done Done) {
113116
ctx, cancel := context.WithCancel(context.Background())
114-
// generate tls cfg
117+
118+
By("generating the TLS config")
115119
certPath := filepath.Join(testenv.WebhookInstallOptions.LocalServingCertDir, "tls.crt")
116120
keyPath := filepath.Join(testenv.WebhookInstallOptions.LocalServingCertDir, "tls.key")
117121

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

129-
// generate listener
133+
By("generating the listener")
130134
listener, err := tls.Listen("tcp",
131135
net.JoinHostPort(testenv.WebhookInstallOptions.LocalServingHost,
132136
strconv.Itoa(int(testenv.WebhookInstallOptions.LocalServingPort))), cfg)
133137
Expect(err).NotTo(HaveOccurred())
134138

135-
// create and register the standalone webhook
136-
hook, err := admission.StandaloneWebhook(&webhook.Admission{Handler: &rejectingValidator{}}, admission.StandaloneOptions{})
139+
By("creating and registering the standalone webhook")
140+
hook, err := admission.StandaloneWebhook(admission.ValidatingWebhookFor(
141+
&admissiontest.FakeValidator{
142+
ErrorToReturn: goerrors.New("Always denied"),
143+
GVKToReturn: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"},
144+
}), admission.StandaloneOptions{})
137145
Expect(err).NotTo(HaveOccurred())
138146
http.Handle("/failing", hook)
139147

140-
// run the http server
148+
By("running the http server")
141149
srv := &http.Server{}
142150
go func() {
143151
idleConnsClosed := make(chan struct{})

0 commit comments

Comments
 (0)